diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..f166060d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single +ij_typescript_use_double_quotes = false + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..804d3533 --- /dev/null +++ b/.gitignore @@ -0,0 +1,64 @@ +src/assets/data_allsettlements_anon_156_v20251217.csv + +# Angular +/dist +/tmp +/out-tsc +/bazel-out + +# Node.js +/node_modules +npm-debug.log +yarn-error.log +package-lock.json +yarn.lock + +# IDE +/.vscode +/.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +.DS_Store + +# Angular CLI +/.angular +/.ng + +# Environment files +/src/environments/*.ts +!/src/environments/environment.ts +!/src/environments/environment.prod.ts + +# Build artifacts +/dist +/e2e +/coverage + +# Testing +/coverage +/.nyc_output + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Optional +.idea/ +.vscode/ +*.sublime-* \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..d6c16d7e --- /dev/null +++ b/.prettierrc @@ -0,0 +1,12 @@ +{ + "printWidth": 100, + "singleQuote": true, + "overrides": [ + { + "files": "*.html", + "options": { + "parser": "angular" + } + } + ] +} diff --git a/README.md b/README.md index 163d41b9..9dce8529 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,27 @@ -# Безопасность веб-приложений. Лабораторка №2 +# Прогноз погоды -## Схема сдачи - -1. Получить задание -2. Сделать форк данного репозитория -3. Выполнить задание согласно полученному варианту -4. Сделать PR (pull request) в данный репозиторий -6. Исправить замечания после code review -7. Получить approve -8. Прийти на занятие и защитить работу - -Что нужно проявить в работе: -- умение разработать завершенное целое веб-приложение, с клиентской и серверной частями (допустимы открытые АПИ) -- навыки верстки на html в объеме 200-300 тегов -- навыки применения css для лейаута и стилизации, желательно с адаптацией к мобилке -- использование jQuery или аналогичных JS-фреймворков -- динамическая подгрузка контента -- динамическое изменение DOM и CSSOM - -Если у вас своя идея по заданию, то расскажите, обсудим и подкорректирую. - -## Вариант 1. Расписания - -Сделать аналог раздела https://ssau.ru/rasp?groupId=531030143 - -Какие нужны возможности: -- справочники групп, табличные данные по расписаниям добывать с настоящего сайта на серверной стороне приложения -- в клиентскую часть подгружать эти сведения динамически по JSON-API -- обеспечить возможность смотреть расписания в разрезе группы или препода -- обеспечить возможность выбора учебной недели (по умолчанию выбирается автоматически) - -## Вариант 2. Аналог Прибывалки для электричек - -Сделать веб-версию Прибывалки, только для электричек - -Какие нужны возможности: -- находить желаемую ЖД-станцию поиском по названию и по карте -- отображать расписания всех проходящих поездов через выбранную станцию -- отображать расписания для поездов между двумя станциями -- работа через АПИ Яндекс.Расписаний https://yandex.ru/dev/rasp/doc/ru/ (доступ получите сами) -- хорошая работа в условиях экрана смартфона -- бонус: функция "любимых остановок" - -## Вариант 3. Прогноз погоды - -Сделать одностраничный сайт с картой, на которой можно выбрать населенный пункт и получить прогноз погоды на несколько дней по нему. - -Какие нужны возможности: - - увидеть на карте точки с населенными пунктами. Координаты населенных пунктов взять из https://tochno.st/datasets/allsettlements - но все 150 тысяч не нужно, выберите 1 тысячу с самым большим населением. - - при нажатии на точку получить всплывающее окошко с графиками изменения температуры, осадков, силы ветра. API для прогнозов возьмите с https://projecteol.ru/ru/ с соблюдением правил. - - графики рисовать каким-нибудь приличным компонентом, например, https://www.chartjs.org/ - - находить населенный пункт по названию - - можете реализовать с собственным серверным компонентом или придумать, как обойтись без него +Веб-приложение для просмотра прогноза погоды по городам России. Приложение использует карту с маркерами городов, поиск и модальные окна для отображения детальной информации. +## Возможности +- 🗺️ Интерактивная карта с маркерами 1000 крупнейших городов России +- 🔍 Поиск городов по названию +- 📊 Детальный прогноз погоды на 7 дней +- 📈 Графики температуры и осадков +- 🌡️ Текущая погода: температура, осадки, ветер, влажность +- 📱 Адаптивный дизайн для мобильных устройств +## Технологии +- Angular 17+ +- Leaflet для карт +- Chart.js для графиков +- Open-Meteo API для данных о погоде +## Установка и запуск +### Клонирование репозитория +```bash +npm install +ng serve \ No newline at end of file diff --git a/angular.json b/angular.json new file mode 100644 index 00000000..0928dba5 --- /dev/null +++ b/angular.json @@ -0,0 +1,74 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "cli": { + "packageManager": "npm" + }, + "newProjectRoot": "projects", + "projects": { + "weather-app": { + "projectType": "application", + "schematics": {}, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular/build:application", + "options": { + "browser": "src/main.ts", + "tsConfig": "tsconfig.app.json", + "assets": [ + { + "glob": "**/*", + "input": "src/assets", + "output": "/assets" + } + ], + "styles": [ + "src/styles.css" + ] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kB", + "maximumError": "1MB" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "4kB", + "maximumError": "8kB" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular/build:dev-server", + "configurations": { + "production": { + "buildTarget": "weather-app:build:production" + }, + "development": { + "buildTarget": "weather-app:build:development" + } + }, + "defaultConfiguration": "development" + }, + "test": { + "builder": "@angular/build:unit-test" + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..1f262340 --- /dev/null +++ b/package.json @@ -0,0 +1,37 @@ +{ + "name": "weather-app", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "test": "ng test" + }, + "private": true, + "packageManager": "npm@10.9.2", + "dependencies": { + "@angular/common": "^21.2.0", + "@angular/compiler": "^21.2.0", + "@angular/core": "^21.2.0", + "@angular/forms": "^21.2.0", + "@angular/platform-browser": "^21.2.0", + "@angular/router": "^21.2.0", + "@types/leaflet": "^1.9.21", + "chart.js": "^4.5.1", + "leaflet": "^1.9.4", + "papaparse": "^5.5.3", + "rxjs": "~7.8.0", + "tslib": "^2.3.0" + }, + "devDependencies": { + "@angular/build": "^21.2.6", + "@angular/cli": "^21.2.6", + "@angular/compiler-cli": "^21.2.0", + "@types/papaparse": "^5.5.2", + "jsdom": "^28.0.0", + "prettier": "^3.8.1", + "typescript": "~5.9.2", + "vitest": "^4.0.8" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 00000000..57614f9c Binary files /dev/null and b/public/favicon.ico differ diff --git a/src/app/app.config.ts b/src/app/app.config.ts new file mode 100644 index 00000000..b78282f3 --- /dev/null +++ b/src/app/app.config.ts @@ -0,0 +1,11 @@ +import { ApplicationConfig } from '@angular/core'; +import { provideRouter } from '@angular/router'; +import { provideHttpClient } from '@angular/common/http'; +import { routes } from './app.routes'; + +export const appConfig: ApplicationConfig = { + providers: [ + provideRouter(routes), + provideHttpClient() + ] +}; \ No newline at end of file diff --git a/src/app/app.css b/src/app/app.css new file mode 100644 index 00000000..72051974 --- /dev/null +++ b/src/app/app.css @@ -0,0 +1,136 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:host { + display: block; + font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; + background: radial-gradient(circle at 20% 30%, #0a0f1e, #05070f); + min-height: 100vh; + padding: 24px; +} + +.dashboard { + max-width: 1300px; + margin: 0 auto; + background: rgba(18, 25, 45, 0.55); + backdrop-filter: blur(16px); + border-radius: 48px; + padding: 28px 32px; + border: 1px solid rgba(90, 150, 220, 0.25); + box-shadow: 0 25px 45px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.05); +} + +.title-section { + text-align: center; + margin-bottom: 32px; +} + +.gradient-title { + font-size: 2.5rem; + font-weight: 700; + background: linear-gradient(135deg, #b9e6ff, #6c9eff, #a07eff); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + display: inline-flex; + align-items: center; + gap: 12px; +} + +.title-icon { + font-size: 2rem; + filter: drop-shadow(0 0 6px rgba(108, 158, 255, 0.6)); +} + +.footer-note { + text-align: center; + font-size: 11px; + margin-top: 32px; + color: #6e7e9e; + letter-spacing: 0.5px; + border-top: 1px dashed rgba(90, 150, 220, 0.2); + padding-top: 20px; +} + +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(5, 8, 18, 0.92); + backdrop-filter: blur(12px); + display: flex; + align-items: center; + justify-content: center; + z-index: 2000; + animation: overlayFade 0.25s ease; +} + +.modal-card { + max-width: 780px; + width: 92%; + max-height: 88vh; + background: linear-gradient(145deg, #0e1628, #080c1a); + border-radius: 48px; + padding: 28px; + overflow-y: auto; + border: 1px solid rgba(80, 140, 220, 0.4); + box-shadow: 0 30px 60px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.05); + animation: modalRise 0.3s cubic-bezier(0.2, 0.9, 0.4, 1.1); + position: relative; +} + +.close-modal { + position: absolute; + top: 20px; + right: 24px; + background: rgba(80, 120, 200, 0.2); + border: none; + color: #b0c8ff; + font-size: 28px; + cursor: pointer; + width: 40px; + height: 40px; + border-radius: 40px; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s; + backdrop-filter: blur(4px); +} + +.close-modal:hover { + background: rgba(80, 120, 200, 0.5); + color: white; + transform: rotate(90deg); +} + +@keyframes overlayFade { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes modalRise { + from { + opacity: 0; + transform: scale(0.96) translateY(20px); + } + to { + opacity: 1; + transform: scale(1) translateY(0); + } +} + +@media (max-width: 720px) { + :host { padding: 12px; } + .dashboard { padding: 18px; } + .gradient-title { font-size: 1.8rem; } +} + +@media (max-width: 520px) { + .modal-card { padding: 20px; } +} \ No newline at end of file diff --git a/src/app/app.html b/src/app/app.html new file mode 100644 index 00000000..d80791e5 --- /dev/null +++ b/src/app/app.html @@ -0,0 +1,26 @@ +
+
+
+ + Прогнозпогоды +
+
+ + + + + + + +
+ + \ No newline at end of file diff --git a/src/app/app.module.ts b/src/app/app.module.ts new file mode 100644 index 00000000..6f4966f2 --- /dev/null +++ b/src/app/app.module.ts @@ -0,0 +1,26 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpClientModule } from '@angular/common/http'; + +import { AppComponent } from './app'; +import { MapComponent } from './components/map/map.component'; +import { SearchComponent } from './components/search/search.component'; +import { WeatherComponent } from './components/weather/weather.component'; + +@NgModule({ + declarations: [ + AppComponent, + MapComponent, + SearchComponent, + WeatherComponent + ], + imports: [ + BrowserModule, + FormsModule, + HttpClientModule + ], + providers: [], + bootstrap: [AppComponent] +}) +export class AppModule { } \ No newline at end of file diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts new file mode 100644 index 00000000..9209eb01 --- /dev/null +++ b/src/app/app.routes.ts @@ -0,0 +1,7 @@ +import { Routes } from '@angular/router'; +import { AppComponent } from './app'; + +export const routes: Routes = [ + { path: '', component: AppComponent }, + { path: '**', redirectTo: '' } +]; \ No newline at end of file diff --git a/src/app/app.ts b/src/app/app.ts new file mode 100644 index 00000000..d98fc9e6 --- /dev/null +++ b/src/app/app.ts @@ -0,0 +1,39 @@ +import { Component, OnInit } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { CityService } from './services/city.service'; +import { CityItem } from './models/city.models'; +import { MapComponent } from './components/map/map.component'; +import { SearchComponent } from './components/search/search.component'; +import { WeatherComponent } from './components/weather/weather.component'; + +@Component({ + selector: 'app-root', + standalone: true, + imports: [CommonModule, MapComponent, SearchComponent, WeatherComponent], + templateUrl: './app.html', + styleUrls: ['./app.css'] +}) +export class AppComponent implements OnInit { + cityList: CityItem[] = []; + selectedCity: CityItem | null = null; + + constructor(private cityService: CityService) {} + + ngOnInit(): void { + this.cityService.fetchCityCatalog().subscribe({ + next: (data) => { + this.cityList = data; + this.cityService.storeCatalog(data); + }, + error: (err) => console.error('City load error:', err) + }); + } + + onCitySelected(city: CityItem): void { + this.selectedCity = city; + } + + dismissModal(): void { + this.selectedCity = null; + } +} \ No newline at end of file diff --git a/src/app/components/map/map.component.css b/src/app/components/map/map.component.css new file mode 100644 index 00000000..3b7a2182 --- /dev/null +++ b/src/app/components/map/map.component.css @@ -0,0 +1,23 @@ +.map-stage { + width: 100%; + height: 500px; + border-radius: 32px; + margin-bottom: 24px; + overflow: hidden; + border: 1px solid rgba(70, 130, 200, 0.4); + box-shadow: 0 12px 28px rgba(0, 0, 0, 0.5); + transition: all 0.2s; + z-index: 1; +} + +.map-stage:hover { + border-color: rgba(90, 160, 240, 0.7); + box-shadow: 0 16px 32px rgba(0, 0, 0, 0.55); +} + +@media (max-width: 700px) { + .map-stage { height: 400px; } +} +@media (max-width: 480px) { + .map-stage { height: 340px; } +} \ No newline at end of file diff --git a/src/app/components/map/map.component.html b/src/app/components/map/map.component.html new file mode 100644 index 00000000..3e3d7492 --- /dev/null +++ b/src/app/components/map/map.component.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/app/components/map/map.component.ts b/src/app/components/map/map.component.ts new file mode 100644 index 00000000..c668e465 --- /dev/null +++ b/src/app/components/map/map.component.ts @@ -0,0 +1,78 @@ +import { Component, AfterViewInit, Input, OnChanges, Output, EventEmitter, ChangeDetectorRef } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import * as L from 'leaflet'; +import { CityItem } from '../../models/city.models'; + +@Component({ + selector: 'app-map', + standalone: true, + imports: [CommonModule], + templateUrl: './map.component.html', + styleUrls: ['./map.component.css'] +}) +export class MapComponent implements AfterViewInit, OnChanges { + @Input() citiesCatalog: CityItem[] = []; + @Output() cityPicked = new EventEmitter(); + + private mapCore: L.Map | null = null; + private markersPool: L.CircleMarker[] = []; + + constructor(private cdr: ChangeDetectorRef) {} + + ngAfterViewInit(): void { + this.initMapSystem(); + } + + ngOnChanges(): void { + if (this.mapCore) this.refreshMarkers(); + } + + private initMapSystem(): void { + const container = document.getElementById('globeContainer'); + if (!container || this.mapCore) return; + + this.mapCore = L.map(container, { + center: [61.5, 95.0], + zoom: 3.8, + zoomControl: true + }); + + L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', { + attribution: '© CartoDB | OpenStreetMap', + subdomains: 'abcd' + }).addTo(this.mapCore); + + setTimeout(() => { + this.mapCore?.invalidateSize(); + this.refreshMarkers(); + }, 120); + } + + private refreshMarkers(): void { + if (!this.mapCore) return; + this.markersPool.forEach(m => m.remove()); + this.markersPool = []; + + this.citiesCatalog.forEach(city => { + const marker = L.circleMarker([city.lat, city.lon], { + radius: 5.5, + color: '#5f9eff', + fillColor: '#2a6eff', + fillOpacity: 0.85, + weight: 1.2 + }).addTo(this.mapCore!); + + marker.bindTooltip(city.name, { direction: 'top' }); + marker.on('click', () => { + this.moveMapTo(city.lat, city.lon); + this.cityPicked.emit(city); + }); + this.markersPool.push(marker); + }); + this.cdr.detectChanges(); + } + + moveMapTo(lat: number, lon: number): void { + this.mapCore?.setView([lat, lon], 8.5, { animate: true }); + } +} \ No newline at end of file diff --git a/src/app/components/search/search.component.css b/src/app/components/search/search.component.css new file mode 100644 index 00000000..2fa5f6ac --- /dev/null +++ b/src/app/components/search/search.component.css @@ -0,0 +1,91 @@ +.search-panel { + position: relative; + margin-bottom: 28px; + z-index: 1000; + width: 100%; +} + +.search-input { + width: 100%; + padding: 16px 22px; + font-size: 15px; + background: rgba(10, 18, 32, 0.7); + border: 1px solid rgba(90, 140, 220, 0.4); + border-radius: 60px; + color: #eef5ff; + backdrop-filter: blur(8px); + transition: all 0.2s; + box-sizing: border-box; +} + +.search-input:focus { + outline: none; + border-color: #6c9eff; + background: rgba(10, 18, 32, 0.9); + box-shadow: 0 0 12px rgba(108, 158, 255, 0.3); +} + +.search-input::placeholder { + color: #6e7e9e; +} + +.results-drop { + position: absolute; + left: 0; + right: 0; + width: 100%; + background: #0f1629e6; + backdrop-filter: blur(16px); + border-radius: 28px; + margin-top: 12px; + border: 1px solid #2a406e; + max-height: 280px; + overflow-y: auto; + display: none; + z-index: 1001; + box-sizing: border-box; +} + +.results-drop.open { + display: block; +} + +.results-drop::-webkit-scrollbar { + width: 6px; +} + +.results-drop::-webkit-scrollbar-track { + background: #0a1020; + border-radius: 10px; +} + +.results-drop::-webkit-scrollbar-thumb { + background: #3a5a8c; + border-radius: 10px; +} + +.results-drop::-webkit-scrollbar-thumb:hover { + background: #5a7ab0; +} + +.result-row { + padding: 12px 20px; + display: flex; + justify-content: space-between; + cursor: pointer; + border-bottom: 1px solid #1f2a44; +} + +.result-row:hover { + background: #1e2b4e; +} + +.city-main { + font-weight: 500; + color: #cae3ff; +} + +.city-pop { + font-size: 12px; + color: #7d96c0; +} \ No newline at end of file diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html new file mode 100644 index 00000000..5ec2d67a --- /dev/null +++ b/src/app/components/search/search.component.html @@ -0,0 +1,20 @@ +
+ +
+
+ {{ item.name }} + {{ formatPop(item.population) }} +
+
+
\ No newline at end of file diff --git a/src/app/components/search/search.component.ts b/src/app/components/search/search.component.ts new file mode 100644 index 00000000..32a91f4a --- /dev/null +++ b/src/app/components/search/search.component.ts @@ -0,0 +1,50 @@ +import { Component, Output, EventEmitter, HostListener } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { CityService } from '../../services/city.service'; +import { CityItem } from '../../models/city.models'; + +@Component({ + selector: 'app-search', + standalone: true, + imports: [CommonModule, FormsModule], + templateUrl: './search.component.html', + styleUrls: ['./search.component.css'] +}) +export class SearchComponent { + queryText = ''; + suggestedCities: CityItem[] = []; + showDropdown = false; + + @Output() cityPicked = new EventEmitter(); + + constructor(private cityService: CityService) {} + + onSearchInput(): void { + if (this.queryText.length < 2) { + this.suggestedCities = []; + this.showDropdown = false; + return; + } + this.suggestedCities = this.cityService.searchLocal(this.queryText); + this.showDropdown = this.suggestedCities.length > 0; + } + + selectCity(city: CityItem): void { + this.queryText = city.name; + this.showDropdown = false; + this.cityPicked.emit(city); + } + + @HostListener('document:click', ['$event']) + closeOnOutside(e: Event): void { + const target = e.target as HTMLElement; + if (!target.closest('.search-panel')) { + this.showDropdown = false; + } + } + + formatPop(pop: number): string { + return this.cityService.formatPop(pop); + } +} \ No newline at end of file diff --git a/src/app/components/weather/weather.component.css b/src/app/components/weather/weather.component.css new file mode 100644 index 00000000..c29e493b --- /dev/null +++ b/src/app/components/weather/weather.component.css @@ -0,0 +1,161 @@ +.weather-pulse { + background: transparent; +} + +.current-glass { + background: rgba(20, 32, 55, 0.6); + border-radius: 44px; + padding: 24px; + text-align: center; + margin-bottom: 24px; + border: 1px solid rgba(90, 150, 255, 0.3); +} + +.city-head { + font-size: 32px; + font-weight: 700; + background: linear-gradient(120deg, #fff, #9bc0ff); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} + +.pop-tag { + font-size: 14px; + color: #8ba4d9; + margin-top: 6px; +} + +.temp-giant { + font-size: 68px; + font-weight: 800; + color: #ffffff; + text-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); + margin: 12px 0; +} + +.weather-tag { + font-size: 18px; + background: #1f2c46; + display: inline-block; + padding: 6px 20px; + border-radius: 60px; + margin-bottom: 20px; +} + +.metrics-row { + display: flex; + justify-content: center; + gap: 20px; + flex-wrap: wrap; +} + +.metric-badge { + background: #0c1325; + padding: 8px 18px; + border-radius: 60px; + text-align: center; + min-width: 100px; +} + +.metric-label { + font-size: 11px; + letter-spacing: 1px; + color: #8ba4d9; +} + +.metric-number { + font-size: 20px; + font-weight: 600; +} + +.toggle-group { + display: flex; + justify-content: center; + gap: 14px; + margin: 20px 0; +} + +.toggle-btn { + background: #101a2e; + border: none; + padding: 8px 28px; + border-radius: 60px; + color: #b8ceff; + font-weight: 500; + cursor: pointer; + transition: 0.2s; +} + +.toggle-btn.active { + background: #2f54b0; + color: white; + box-shadow: 0 0 10px #2f54b0; +} + +.chart-frame { + background: #07102180; + border-radius: 32px; + padding: 16px; + margin: 20px 0; + border: 1px solid #2f4580; +} + +.week-list { + display: flex; + overflow-x: auto; + gap: 14px; + padding: 8px 0; +} + +.day-card { + background: #0f182eb3; + border-radius: 32px; + padding: 14px 18px; + min-width: 100px; + text-align: center; + transition: 0.2s; +} + +.day-card:hover { + background: #1a2a4e; + transform: translateY(-3px); +} + +.day-icon { + font-size: 36px; + margin: 8px 0; +} + +.day-temp-high { + font-size: 20px; + font-weight: 700; +} + +.day-temp-low { + font-size: 13px; + opacity: 0.7; +} + +.precip-value { + font-size: 11px; + margin-top: 8px; +} + +.loader-ring { + text-align: center; + padding: 40px; + font-size: 18px; + color: #9bbdff; +} + +.error-message { + text-align: center; + padding: 40px; + color: #ffac9e; +} + +.empty-hint { + text-align: center; + padding: 30px; +} \ No newline at end of file diff --git a/src/app/components/weather/weather.component.html b/src/app/components/weather/weather.component.html new file mode 100644 index 00000000..8c9bd73a --- /dev/null +++ b/src/app/components/weather/weather.component.html @@ -0,0 +1,60 @@ +
+
+
Загрузка атмосферных данных...
+
+ +
+
Не удалось получить прогноз
+
+ +
+
+
{{ cityData.name }}
+
🏙️ {{ formatPop(cityData.population) }}
+ +
{{ formatTemp(weatherBundle.current.temperature_2m) }}°
+
+ {{ getWeatherPhrase(weatherBundle.current.weathercode) }} + {{ getWeatherSymbol(weatherBundle.current.weathercode) }} +
+ +
+
+
Осадки
+
{{ weatherBundle.current.precipitation?.toFixed(1) || 0 }} мм
+
+
+
Ветер
+
{{ Math.round(weatherBundle.current.wind_speed_10m) }} км/ч
+
+
+
Влажность
+
{{ weatherBundle.current.relative_humidity_2m || '—' }} %
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+
{{ getWeatherSymbol(weatherBundle.daily.weathercode[idx]) }}
+
{{ getDayLabel(day, idx === 0) }}
+
{{ formatTemp(weatherBundle.daily.temperature_2m_max[idx]) }}°
+
{{ formatTemp(weatherBundle.daily.temperature_2m_min[idx]) }}°
+
💧 {{ weatherBundle.daily.precipitation_sum[idx]?.toFixed(1) || 0 }} мм
+
+
+
+
+ +
+ Выберите город на карте или через поиск +
\ No newline at end of file diff --git a/src/app/components/weather/weather.component.ts b/src/app/components/weather/weather.component.ts new file mode 100644 index 00000000..7fc27fe8 --- /dev/null +++ b/src/app/components/weather/weather.component.ts @@ -0,0 +1,117 @@ +import { Component, Input, OnChanges, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { CityItem, WeatherDataSet } from '../../models/city.models'; +import { WeatherService } from '../../services/weather.service'; +import { CityService } from '../../services/city.service'; +import Chart from 'chart.js/auto'; + +@Component({ + selector: 'app-weather', + standalone: true, + imports: [CommonModule], + templateUrl: './weather.component.html', + styleUrls: ['./weather.component.css'] +}) +export class WeatherComponent implements OnChanges { + @Input() cityData: CityItem | null = null; + @ViewChild('weatherCanvas') canvasRef!: ElementRef; + + weatherBundle: WeatherDataSet | null = null; + isBusy = false; + hasErrorFlag = false; + activeMetric: 'temp' | 'rain' = 'temp'; + + private chartInstance: Chart | null = null; + readonly Math = Math; + + constructor( + private weatherApi: WeatherService, + private cityUtil: CityService, + private cdr: ChangeDetectorRef + ) {} + + ngOnChanges(): void { + if (this.cityData) this.loadWeatherData(); + } + + private loadWeatherData(): void { + if (!this.cityData) return; + this.isBusy = true; + this.hasErrorFlag = false; + this.weatherBundle = null; + this.cdr.detectChanges(); + + this.weatherApi.fetchWeather(this.cityData.lat, this.cityData.lon).subscribe({ + next: (data) => { + this.weatherBundle = data; + this.isBusy = false; + this.cdr.detectChanges(); + setTimeout(() => this.renderChart(), 80); + }, + error: () => { + this.isBusy = false; + this.hasErrorFlag = true; + this.cdr.detectChanges(); + } + }); + } + + setMetric(metric: 'temp' | 'rain'): void { + this.activeMetric = metric; + this.renderChart(); + } + + private renderChart(): void { + if (!this.weatherBundle || !this.canvasRef) return; + if (this.chartInstance) { + this.chartInstance.destroy(); + this.chartInstance = null; + } + const ctx = this.canvasRef.nativeElement.getContext('2d'); + if (!ctx) return; + + const daily = this.weatherBundle.daily; + const isTempMode = this.activeMetric === 'temp'; + const dataSet = isTempMode ? daily.temperature_2m_max : daily.precipitation_sum; + const labelText = isTempMode ? 'Температура (Celsius)' : 'Сумма осадков (mm)'; + const lineColor = isTempMode ? '#7fb0ff' : '#60d0a0'; + const fillColor = isTempMode ? 'rgba(127, 176, 255, 0.1)' : 'rgba(96, 208, 160, 0.1)'; + + this.chartInstance = new Chart(ctx, { + type: 'line', + data: { + labels: daily.time.map((t, idx) => this.getDayLabel(t, idx === 0)), + datasets: [{ + label: labelText, + data: dataSet, + borderColor: lineColor, + backgroundColor: fillColor, + borderWidth: 2.5, + pointRadius: 4, + pointBackgroundColor: lineColor, + pointBorderColor: '#0a1020', + tension: 0.25, + fill: true + }] + }, + options: { + responsive: true, + maintainAspectRatio: true, + plugins: { + legend: { labels: { color: '#bfd6ff' } }, + tooltip: { backgroundColor: '#0e162e', titleColor: '#cae0ff', bodyColor: '#9db9f0' } + }, + scales: { + y: { ticks: { color: '#cae0ff' }, grid: { color: '#2a3a6040' } }, + x: { ticks: { color: '#cae0ff' }, grid: { display: false } } + } + } + }); + } + + getWeatherSymbol(code: number): string { return this.weatherApi.getWeatherSymbol(code); } + getWeatherPhrase(code: number): string { return this.weatherApi.getWeatherPhrase(code); } + getDayLabel(date: string, isToday: boolean): string { return this.weatherApi.formatDayLabel(date, isToday); } + formatTemp(t: number): string { return Math.round(t).toString(); } + formatPop(p: number): string { return this.cityUtil.formatPop(p); } +} \ No newline at end of file diff --git a/src/app/models/city.models.ts b/src/app/models/city.models.ts new file mode 100644 index 00000000..519774fe --- /dev/null +++ b/src/app/models/city.models.ts @@ -0,0 +1,27 @@ +export interface CityItem { + name: string; + lat: number; + lon: number; + population: number; +} + +export interface CurrentWeather { + temperature_2m: number; + precipitation: number; + wind_speed_10m: number; + relative_humidity_2m: number; + weathercode: number; +} + +export interface DailyForecastSet { + time: string[]; + weathercode: number[]; + temperature_2m_max: number[]; + temperature_2m_min: number[]; + precipitation_sum: number[]; +} + +export interface WeatherDataSet { + current: CurrentWeather; + daily: DailyForecastSet; +} \ No newline at end of file diff --git a/src/app/services/city.service.ts b/src/app/services/city.service.ts new file mode 100644 index 00000000..22ba0da1 --- /dev/null +++ b/src/app/services/city.service.ts @@ -0,0 +1,71 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable, map } from 'rxjs'; +import * as Papa from 'papaparse'; +import { CityItem } from '../models/city.models'; + +@Injectable({ providedIn: 'root' }) +export class CityService { + private catalog: CityItem[] = []; + + constructor(private http: HttpClient) {} + + fetchCityCatalog(): Observable { + return this.http.get('/assets/top1000_cities.csv', { responseType: 'text' }) + .pipe( + map(csv => { + const parsed = Papa.parse(csv, { + header: true, + skipEmptyLines: true + }); + + return parsed.data.map((row: any) => ({ + name: row.name, + lat: parseFloat(row.lat), + lon: parseFloat(row.lon), + population: parseInt(row.population, 10) + })); + }) + ); + } + + storeCatalog(data: CityItem[]): void { + this.catalog = data; + } + + getCatalog(): CityItem[] { + return this.catalog; + } + + searchLocal(query: string): CityItem[] { + if (!query || query.length < 2) return []; + + const q = query.toLowerCase(); + + return this.catalog + .map(c => ({ + ...c, + _rank: this.getMatchScore(c.name.toLowerCase(), q) + })) + .filter(c => c._rank > 0) + .sort((a, b) => b._rank - a._rank) + .slice(0, 8); + } + + private getMatchScore(name: string, query: string): number { + if (name === query) return 4; + if (name.startsWith(query)) return 3; + if (name.includes(query)) return 2; + return 0; + } + + formatPop(pop: number): string { + if (pop >= 1_000_000) { + return (pop / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'M'; + } + if (pop >= 1_000) { + return Math.round(pop / 1_000) + 'K'; + } + return String(pop); + } +} \ No newline at end of file diff --git a/src/app/services/weather.service.ts b/src/app/services/weather.service.ts new file mode 100644 index 00000000..9d82c845 --- /dev/null +++ b/src/app/services/weather.service.ts @@ -0,0 +1,52 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable, map } from 'rxjs'; +import { WeatherDataSet } from '../models/city.models'; + +@Injectable({ providedIn: 'root' }) +export class WeatherService { + private apiBase = 'https://api.open-meteo.com/v1/forecast'; + + constructor(private http: HttpClient) {} + + fetchWeather(lat: number, lon: number): Observable { + const url = `${this.apiBase}?latitude=${lat}&longitude=${lon}¤t=temperature_2m,precipitation,wind_speed_10m,relative_humidity_2m,weathercode&daily=weathercode,temperature_2m_max,temperature_2m_min,precipitation_sum&timezone=auto&forecast_days=7`; + return this.http.get(url); + } + + getWeatherSymbol(code: number): string { + const mapping: Record = { + 0: '✨', 1: '🌤️', 2: '⛅', 3: '☁️', + 45: '🌫️', 48: '❄️🌫️', + 51: '💧', 53: '💧💧', 55: '💧💧💧', + 56: '🧊', 57: '🧊❄️', + 61: '🌦️', 63: '🌧️', 65: '🌧️🌧️', + 66: '🌧️❄️', 67: '⛈️❄️', + 71: '❄️', 73: '❄️❄️', 75: '❄️❄️❄️', + 77: '🌨️', + 80: '🌦️', 81: '🌧️', 82: '⛈️', + 85: '🌨️', 86: '🌨️🌨️', + 95: '⚡🌩️', 96: '⚡🧊', 99: '⚡⚡🧊' + }; + return mapping[code] || '🌡️'; + } + + getWeatherPhrase(code: number): string { + const phrases: Record = { + 0: 'Без осадков', 1: 'Солнечно', 2: 'Облачно', 3: 'Пасмурно', + 45: 'Туманно', 48: 'Туман с изморозью', + 51: 'Морось', 53: 'Умеренная морось', 55: 'Сильная морось', + 61: 'Дождь', 63: 'Ливень', 65: 'Сильный ливень', + 71: 'Снег', 73: 'Снегопад', 75: 'Метель', + 80: 'Кратковременный дождь', 95: 'Грозовые разряды' + }; + return phrases[code] || 'Переменная облачность'; + } + + formatDayLabel(dateString: string, isNow: boolean = false): string { + if (isNow) return 'Сегодня'; + const week = ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб']; + const dt = new Date(dateString); + return week[dt.getDay()]; + } +} \ No newline at end of file diff --git a/src/assets/main.py b/src/assets/main.py new file mode 100644 index 00000000..4b854f56 --- /dev/null +++ b/src/assets/main.py @@ -0,0 +1,42 @@ +import csv + +INPUT_FILE = "data_allsettlements_anon_156_v20251217.csv" +OUTPUT_FILE = "top1000_cities.csv" + +cities = [] + +with open(INPUT_FILE, encoding="utf-8") as f: + reader = csv.DictReader(f, delimiter=';') + + for row in reader: + if row["object_level"] not in ["Населенный пункт", "Город федерального значения"]: + continue + + try: + name = row["settlement"] + lat = float(row["latitude_dadata"]) + lon = float(row["longitude_dadata"]) + population = int(row["population"]) + except (ValueError, TypeError): + continue + + if not name: + continue + + cities.append({ + "name": name, + "lat": lat, + "lon": lon, + "population": population + }) + +cities.sort(key=lambda x: x["population"], reverse=True) + +top_cities = cities[:1000] + +with open(OUTPUT_FILE, "w", newline='', encoding="utf-8") as f: + writer = csv.DictWriter(f, fieldnames=["name", "lat", "lon", "population"]) + writer.writeheader() + writer.writerows(top_cities) + +print("top1000_cities.csv") \ No newline at end of file diff --git a/src/assets/top1000_cities.csv b/src/assets/top1000_cities.csv new file mode 100644 index 00000000..c643100e --- /dev/null +++ b/src/assets/top1000_cities.csv @@ -0,0 +1,1001 @@ +name,lat,lon,population +г. Новосибирск,55.030187,82.920426,1633595 +г. Екатеринбург,56.8387061,60.6054943,1544376 +г. Казань,55.7944326,49.1115164,1308660 +г. Нижний Новгород,56.326794,44.006495,1226076 +г. Челябинск,55.1602292,61.4007614,1189525 +г. Красноярск,56.0095312,92.8525234,1187771 +г. Самара,53.1951774,50.1069625,1173299 +г. Уфа,54.734856,55.9577802,1144809 +г. Ростов-на-Дону,47.2180329,39.6902714,1142162 +г. Омск,54.9849581,73.3675684,1125695 +г. Краснодар,45.035453,38.975301,1099344 +г. Воронеж,51.6593943,39.196922,1057681 +г. Пермь,58.0102668,56.2342725,1034002 +г. Волгоград,48.7071653,44.5170212,1028036 +г. Саратов,51.533557,46.034257,901361 +г. Тюмень,57.1531178,65.5343535,847488 +г. Тольятти,53.5205003,49.3895011,684709 +г. Барнаул,53.3479774,83.7798977,630877 +г. Ижевск,56.8528384,53.211509,623472 +г. Махачкала,42.9849039,47.5045541,623254 +г. Хабаровск,48.4648124,135.0598539,617441 +г. Ульяновск,54.3079032,48.3748473,617352 +г. Иркутск,52.2863483,104.2806793,617264 +г. Владивосток,43.1163208,131.8824988,603519 +г. Ярославль,57.6216293,39.8978921,577279 +г. Кемерово,55.3910176,86.0469193,557119 +г. Томск,56.4846736,84.9482929,556478 +г. Набережные Челны,55.6948843,52.3279115,548434 +г. Ставрополь,45.0444563,41.9691349,547443 +г. Оренбург,51.7875335,55.1017803,543654 +г. Новокузнецк,53.7943459,87.2142908,537480 +г. Рязань,54.6255345,39.7359162,528599 +г. Балашиха,55.796991,37.938104,520962 +г. Пенза,53.1753947,45.0347408,501109 +г. Чебоксары,56.125485,47.377328,497807 +г. Липецк,52.6101389,39.5947287,496403 +г. Калининград,54.7074298,20.5073482,490449 +г. Астрахань,46.3656435,48.0559229,475629 +г. Тула,54.1918898,37.6153644,473622 +г. Киров,58.6034972,49.6680445,468212 +г. Сочи,43.5855182,39.7229922,466078 +г. Курск,51.7303825,36.1925546,440052 +г. Улан-Удэ,51.8334492,107.584068,437565 +г. Тверь,56.8586556,35.9118279,416219 +г. Магнитогорск,53.4072599,58.9791822,410594 +г. Сургут,61.2541492,73.396236,396443 +г. Брянск,53.2420053,34.3653002,379152 +г. Иваново,56.9994066,40.9729071,361644 +г. Якутск,62.0280605,129.7324858,355443 +г. Владимир,56.1280444,40.4082983,349951 +г. Симферополь,44.9482789,34.1001275,340540 +г. Белгород,50.5975582,36.5858422,339978 +г. Нижний Тагил,57.9102289,59.9814188,338966 +г. Калуга,54.506025,36.2516145,337058 +г. Чита,52.0338828,113.499487,334427 +г. Грозный,43.3178923,45.6981421,328533 +г. Волжский,48.7979775,44.7462572,321479 +город Смоленск,54.782635,32.045251,316570 +г. Подольск,55.4389616,37.5703052,314934 +г. Саранск,54.1808234,45.1863143,314871 +г. Вологда,59.220501,39.891523,313944 +г. Курган,55.4443683,65.3162142,310911 +г. Череповец,59.1268743,37.9090556,305185 +г. Орёл,52.9671928,36.0695725,303169 +г. Архангельск,64.53939,40.5170011,301199 +г. Владикавказ,43.020552,44.681905,295830 +г. Нижневартовск,60.9397399,76.5695505,283256 +г. Йошкар-Ола,56.6343266,47.8999167,281248 +г. Стерлитамак,53.6302062,55.9317313,277410 +г. Мурманск,68.970663,33.074918,270384 +г. Кострома,57.768,40.927,267481 +г. Новороссийск,44.7234226,37.7686906,262293 +г. Тамбов,52.7211576,41.4522156,261803 +г. Химки,55.8888467,37.430372,257128 +г. Мытищи,55.9104655,37.7363923,255429 +г. Нальчик,43.4846449,43.6070943,247054 +г. Таганрог,47.2096599,38.9352459,245120 +г. Нижнекамск,55.6312304,51.8144719,241479 +г. Благовещенск,50.290659,127.527198,241437 +г. Комсомольск-на-Амуре,50.5525092,136.9895507,238505 +г. Петрозаводск,61.7889739,34.3596538,234897 +г. Королёв,55.9161885,37.854422,228095 +г. Шахты,47.7085649,40.2158665,226452 +г. Энгельс,51.4855068,46.1267008,225428 +г. Великий Новгород,58.5214164,31.2754186,224286 +г. Люберцы,55.676499,37.898125,224195 +г. Братск,56.1514087,101.6341027,224071 +г. Старый Оскол,51.297974,37.833231,221676 +город Ангарск,52.544898,103.8884509,221296 +г. Сыктывкар,61.6687212,50.8356788,220580 +г. Дзержинск,56.2375332,43.4598979,218630 +г. Псков,57.819825,28.3950685,193082 +г. Орск,51.2292952,58.4752502,189195 +г. Красногорск,55.8318647,37.3294489,187634 +г. Армавир,45.0011356,41.1324283,187177 +г. Абакан,53.7223055,91.4436926,184769 +г. Балаково,52.0222817,47.7827796,184466 +г. Бийск,52.5392784,85.213843,183852 +г. Южно-Сахалинск,46.9667029,142.7212958,181587 +г. Одинцово,55.6790296,37.2635177,180530 +г. Уссурийск,43.8048438,131.9367538,180393 +г. Прокопьевск,53.8604228,86.7183302,177819 +г. Рыбинск,58.0484021,38.858475,177295 +г. Норильск,69.3489906,88.2009379,174453 +г. Волгодонск,47.5165757,42.1984573,168048 +г. Сызрань,53.1557162,48.4744217,165725 +г. Петропавловск-Камчатский,53.0370074,158.65595,164900 +г. Каменск-Уральский,56.4148539,61.9188448,164192 +г. Новочеркасск,47.4118469,40.1040646,163674 +г. Альметьевск,54.9014385,52.297123,163512 +г. Златоуст,55.1714213,59.6726478,161774 +г. Северодвинск,64.5625626,39.8182183,157213 +г. Хасавюрт,43.2504341,46.5850867,155144 +г. Керчь,45.3561252,36.4673129,154621 +г. Домодедово,55.436403,37.7666001,152404 +г. Салават,53.362823,55.9154367,148575 +г. Миасс,55.0552642,60.0791765,147995 +г. Копейск,55.1167381,61.6179305,147806 +г. Пятигорск,44.041234,43.0660504,146473 +г. Электросталь,55.784633,38.444699,146403 +г. Майкоп,44.609792,40.1005698,143385 +г. Находка,42.8111483,132.8844502,139931 +г. Березники,59.4079119,56.8039179,138069 +г. Коломна,55.1026926,38.7530213,134850 +г. Щёлково,55.9233436,37.9783923,134211 +г. Серпухов,54.9226176,37.4033624,133793 +г. Ковров,56.3554229,41.3171096,132417 +г. Нефтекамск,56.0883752,54.2482411,131942 +г. Кисловодск,43.9052745,42.7167964,127521 +г. Батайск,47.1382139,39.750662,126988 +г. Рубцовск,51.5012963,81.2078042,126834 +г. Обнинск,55.0944881,36.6121565,125376 +г. Кызыл,51.7190588,94.4376984,125241 +г. Дербент,42.0590354,48.2908599,124953 +г. Нефтеюганск,61.0881688,72.6163369,124732 +г. Назрань,43.2256598,44.7646901,122350 +г. Каспийск,42.8916263,47.6366936,121140 +г. Долгопрудный,55.9385975,37.5100337,120907 +г. Новочебоксарск,56.1095538,47.4791596,120375 +г. Новомосковск,54.010957,38.2915047,119697 +г. Ессентуки,44.0444693,42.8589782,119658 +г. Невинномысск,44.6226742,41.9476424,117562 +г. Октябрьский,54.4814637,53.4654836,115557 +г. Раменское,55.5495378,38.2728835,114537 +г. Первоуральск,56.9080096,59.9429936,114450 +г. Михайловск,45.1297467,42.0287477,114133 +г. Реутов,55.7582708,37.8618288,113871 +г. Черкесск,44.228353,42.048278,113226 +г. Жуковский,55.5999747,38.1224066,111222 +г. Димитровград,54.2168413,49.6262388,110968 +г. Пушкино,56.0104754,37.847161,110868 +г. Артем,43.3501868,132.1595835,109556 +г. Камышин,50.0652955,45.384535,107927 +г. Евпатория,45.190629,33.367634,107877 +г. Муром,55.563153,42.0230298,107497 +г. Ханты-Мансийск,61.0025598,69.0183366,107473 +г. Новый Уренгой,66.0839904,76.6810104,107251 +г. Северск,56.6032343,84.881027,106648 +г. Орехово-Зуево,55.8164825,38.9368137,105745 +г. Арзамас,55.3946343,43.8408135,104908 +г. Ногинск,55.8760353,38.4231801,103891 +г. Новошахтинск,47.7576743,39.9364541,103480 +г. Бердск,54.7582184,83.1071527,102850 +г. Элиста,46.30821,44.2702746,102583 +г. Сергиев Посад,56.3063854,38.1502956,101756 +г. Видное,55.5517857,37.7062236,101490 +г. Ачинск,56.2537315,90.4793969,100621 +г. Тобольск,58.2017257,68.2538473,100352 +г. Ноябрьск,63.1920786,75.4454918,100188 +г. Елец,52.6152577,38.528899,99875 +г. Зеленодольск,55.8465861,48.500966,99137 +г. Новокуйбышевск,53.0994719,49.9477255,98306 +г. Воткинск,57.0518828,53.9874914,97471 +г. Железногорск,52.3379241,35.3517678,97038 +г. Междуреченск,53.6865918,88.0702782,96174 +г. Воскресенск,55.3070155,38.7028385,95495 +г. Гатчина,59.5651362,30.1281234,94377 +г. Серов,59.6047459,60.5752389,94211 +г. Саров,54.922813,43.3447953,93357 +г. Ленинск-Кузнецкий,54.6674801,86.1796673,92244 +г. Сарапул,56.4616582,53.8036826,91115 +г. Магадан,59.5681947,150.8086939,90757 +г. Мичуринск,52.8913406,40.5103713,90451 +г. Соликамск,59.6483298,56.7710196,89473 +г. Мурино,60.0448984,30.4573012,89083 +г. Чехов,55.1506335,37.4532854,89025 +г. Клин,56.3424345,36.7240443,88511 +г. Бузулук,52.7881715,52.2623964,88341 +г. Глазов,58.1359039,52.6634921,87762 +г. Канск,56.2050971,95.7051994,86816 +г. Великие Луки,56.343703,30.515671,86711 +г. Каменск-Шахтинский,48.3204742,40.2689608,86365 +г. Губкин,51.2836227,37.5347995,85225 +г. Киселевск,54.0383268,86.6605444,83431 +г. Ейск,46.7114714,38.2764767,82943 +г. Ивантеевка,55.9741839,37.9208717,82827 +г. Лобня,56.0328978,37.4614808,82764 +г. Железногорск,56.2528775,93.532226,82723 +г. Азов,47.1122112,39.4233596,81924 +г. Анапа,44.8948984,37.3162896,81863 +г. Бугульма,54.5364489,52.7894083,81677 +г. Московский,55.597255,37.359448,81309 +г. Геленджик,44.5631183,38.0791049,80204 +г. Ухта,63.5563841,53.7013827,79899 +г. Юрга,55.7202352,84.8885927,79693 +г. Усть-Илимск,58.0189147,102.6855314,79570 +г. Всеволожск,60.0190286,30.6456654,79038 +г. Новоуральск,57.2472236,60.0955422,78479 +г. Кузнецк,53.1130584,46.6052642,78390 +г. Бор,56.3565886,44.0645547,78372 +г. Кинешма,57.442535,42.1689258,77694 +г. Озерск,55.7632143,60.7076521,76896 +г. Новотроицк,51.1963401,58.3017089,75960 +г. Кропоткин,45.4332835,40.5728945,75858 +г. Чайковский,56.7780683,54.1477844,75837 +г. Черногорск,53.8258374,91.3259463,75745 +г. Усолье-Сибирское,52.7566823,103.6387415,74762 +г. Ялта,44.4952969,34.1663516,74652 +г. Дубна,56.7416155,37.1756531,74183 +г. Балашов,51.5388261,43.1839668,74057 +посёлок Коммунарка,55.570388,37.475469,73735 +г. Елабуга,55.7566788,52.0545017,73630 +г. Новоалтайск,53.4120027,83.9309813,73049 +г. Выборг,60.7129589,28.7328799,72530 +г. Егорьевск,55.3831202,39.0358883,71686 +г. Верхняя Пышма,56.9758868,60.5649684,71335 +г. Наро-Фоминск,55.386185,36.734484,71121 +г. Минеральные Воды,44.2087295,43.1383447,70485 +г. Троицк,54.0843322,61.5587093,70301 +г. Чапаевск,52.929023,49.8673246,70228 +г. Минусинск,53.7104585,91.6871667,70089 +г. Биробиджан,48.7946217,132.9217228,70064 +г. Шадринск,56.0871041,63.6297172,68609 +г. Белово,54.4221568,86.3037406,68542 +г. Туймазы,54.5999395,53.6950191,68349 +г. Сертолово,60.1446697,30.209571,68241 +г. Буйнакск,42.8213541,47.116407,68121 +г. Ишим,56.1104734,69.4797226,67614 +г. Кирово-Чепецк,58.5560037,50.0317344,66651 +г. Анжеро-Судженск,56.0787454,86.0200409,66583 +г. Феодосия,45.0320187,35.382384,66293 +г. Дмитров,56.3476745,37.5266195,65574 +г. Сосновый Бор,59.904224,29.092209,65367 +г. Горно-Алтайск,51.9581885,85.9603499,65342 +г. Лыткарино,55.5778267,37.9034779,65212 +г. Павловский Посад,55.780723,38.6596371,65098 +г. Троицк,55.4844981,37.3067485,65043 +г. Белорецк,53.967626,58.4100433,64525 +г. Ступино,54.886274,38.078228,64412 +г. Гудермес,43.3518339,46.1034832,64376 +г. Ишимбай,53.4545688,56.0440089,64041 +г. Донской,53.9678617,38.3372254,63837 +г. Котельники,55.6599375,37.8631583,63728 +г. Кстово,56.1432079,44.1663972,63646 +г. Урус-Мартан,43.120175,45.539276,63449 +г. Георгиевск,44.14794,43.474254,63221 +г. Клинцы,52.752875,32.2337792,63059 +г. Нягань,62.1454886,65.3945936,63034 +г. Славянск-на-Кубани,45.2604694,38.1259659,62985 +г. Кунгур,57.4284056,56.9438416,62673 +город Сунжа,43.3203629,45.0477848,62078 +г. Туапсе,44.1104007,39.0825379,61571 +г. Когалым,62.2639797,74.482946,61441 +г. Белогорск,50.921219,128.4737866,61440 +г. Лениногорск,54.5966119,52.4433347,60993 +город Россошь,50.1701985,39.6226453,60879 +г. Алексин,54.5084968,37.0478364,60842 +г. Кудрово,59.9076688,30.5119611,60791 +г. Борисоглебск,51.3654207,42.1009542,60687 +г. Фрязино,55.9589291,38.0409827,60580 +г. Гуково,48.0450292,39.9485638,60361 +г. Ревда,56.7987642,59.9071644,60200 +г. Прохладный,43.7590107,44.010051,59938 +г. Березовский,56.9136462,60.7852371,59698 +г. Белебей,54.1034535,54.1112181,59195 +г. Чистополь,55.3699331,50.6285823,58815 +г. Заречный,53.1961885,45.1691136,58510 +г. Будённовск,44.781467,44.164948,58103 +г. Кумертау,52.756471,55.7970469,57949 +г. Сальск,46.475234,41.541039,57937 +г. Дзержинский,55.6241057,37.8441593,57918 +г. Лабинск,44.6354147,40.7244209,57428 +г. Асбест,57.0052534,61.4581769,57317 +г. Искитим,54.626704,83.2949994,57147 +г. Павлово,55.965103,43.064848,57116 +г. Александров,56.3918756,38.7110582,57053 +г. Воркута,67.497434,64.0611813,56985 +г. Щербинка,55.50868,37.5633253,56531 +г. Сибай,52.7204622,58.6663921,56514 +г. Мелеуз,52.9589874,55.9282514,56505 +г. Котлас,61.2528975,46.6332216,56093 +г. Михайловка,50.0708708,43.2401092,56031 +г. Избербаш,42.5652081,47.8710684,55996 +г. Краснотурьинск,59.7638319,60.1935754,55875 +г. Белореченск,44.7652692,39.8781164,55870 +г. Ржев,56.2629154,34.3290948,55757 +г. Лесосибирск,58.2216981,92.503692,55730 +г. Тихорецк,45.8546923,40.1258776,55686 +г. Тихвин,59.644619,33.54193,55415 +г. Шуя,56.8507513,41.3516168,55225 +г. Полевской,56.4958618,60.2366252,55182 +г. Щекино,54.0021718,37.5177177,55109 +г. Шали,43.1487442,45.9010465,55054 +г. Вольск,52.0459603,47.3873,55035 +г. Крымск,44.9343723,37.9854857,54597 +пгт Яблоновский,44.981266,38.936362,54291 +г. Зеленогорск,56.1133542,94.5889359,54279 +г. Лиски,50.9945381,39.5183454,54147 +г. Черемхово,53.1233358,103.1574108,53958 +г. Лысьва,58.0996742,57.8087369,53855 +г. Нерюнгри,56.6599502,124.7201885,53409 +г. Волжск,55.8623164,48.3715777,53013 +г. Мегион,61.0318864,76.102504,52887 +г. Вязьма,55.2116645,34.2952096,51950 +г. Тимашевск,45.6158949,38.9351457,51858 +г. Гусь-Хрустальный,55.6199041,40.6578219,51552 +г. Краснокаменск,50.09868,118.034118,51137 +г. Кириши,59.449699,32.008705,51028 +пгт Нахабино рп,55.840381,37.175899,50916 +г. Снежинск,56.0852853,60.73251,50619 +г. Жигулевск,53.4012735,49.4944877,50466 +г. Кизляр,43.8484072,46.7232534,49999 +г. Кингисепп,59.3741261,28.611223,49716 +г. Апатиты,67.567731,33.4067789,49647 +г. Узловая,53.9731953,38.1764288,49427 +г. Краснокамск,58.0820673,55.7478889,48778 +г. Балахна,56.4950365,43.575846,48569 +г. Свободный,51.3612532,128.122028,48517 +г. Солнечногорск,56.185102,36.977631,48413 +г. Аксай,47.2675888,39.8755792,48372 +г. Лесной,58.6349153,59.7980136,48261 +г. Арсеньев,44.1621626,133.2696658,47937 +г. Салехард,66.5493706,66.6084227,47910 +г. Боровичи,58.3840076,33.9176708,47883 +г. Рассказово,52.6538108,41.8743764,47644 +г. Курганинск,44.8877061,40.5914627,47305 +г. Отрадный,53.380127,51.3440385,46984 +г. Донецк,48.3350869,39.9459603,46623 +г. Надым,65.528146,72.514417,45973 +г. Кашира,54.8532793,38.1904181,45922 +г. Вышний Волочек,57.5684471,34.5404365,45830 +г. Чусовой,58.2975271,57.8193629,45471 +г. Рославль,53.9449217,32.847942,45416 +г. Назарово,56.0115024,90.4169443,45333 +г. Выкса,55.3206313,42.1679983,45240 +г. Саяногорск,53.1007127,91.4122756,44872 +г. Чебаркуль,54.9818594,60.3774264,44693 +г. Канаш,55.5068806,47.4917914,44354 +г. Можга,56.4427514,52.2137584,44345 +г. Бирск,55.4156358,55.5583061,44295 +г. Березовский,55.6693866,86.2745058,44073 +г. Грязи,52.4872943,39.9331152,43908 +г. Краснознаменск,55.5978331,37.039529,43868 +г. Бугуруслан,53.6522761,52.4326104,43593 +г. Радужный,62.1342204,77.458477,43577 +г. Ливны,52.4286428,37.6040201,43549 +г. Североморск,69.07651,33.4178343,43327 +г. Карабулак,43.3055756,44.9095113,43037 +г. Рузаевка,54.0582232,44.949083,42989 +г. Лангепас,61.2537123,75.1806961,42701 +г. Сатка,55.0404006,59.0288229,42597 +г. Шелехов,52.2101358,104.0973332,41998 +г. Куйбышев,55.445949,78.311108,41946 +г. Малоярославец,55.0177696,36.4633694,41836 +г. Кореновск,45.4642106,39.4589751,41826 +г. Большой Камень,43.1111521,132.3479458,41825 +станица Каневская,46.0847521,38.9719273,41721 +г. Аргун,43.2917917,45.8722923,41622 +г. Темрюк,45.2610243,37.4455473,41608 +г. Ярцево,55.0565468,32.6902745,41452 +г. Урай,60.1297244,64.8038858,41315 +г. Заринск,53.7064163,84.93148,41272 +г. Торжок,57.041349,34.9602076,41116 +г. Верхняя Салда,58.0466272,60.5560133,41034 +г. Лянтор,61.6392893,72.1793962,40977 +г. Горячий Ключ,44.6344393,39.1355285,40903 +г. Кимры,56.8732554,37.3557008,40875 +г. Мариинск,56.2128227,87.7454299,40779 +г. Белая Калитва,48.176882,40.8032881,40448 +г. Сосновоборск,56.120075,93.3354461,40442 +г. Осинники,53.598681,87.3371253,40367 +г. Курчатов,51.6605387,35.6571025,40318 +г. Апшеронск,44.4583753,39.7301418,40289 +г. Пыть-Ях,60.7586475,72.8366942,40180 +г. Усть-Лабинск,45.2226625,39.6929278,40158 +г. Пугачев,52.0159472,48.797175,40127 +г. Мыски,53.7126111,87.8056844,40109 +г. Мончегорск,67.9386512,32.9359042,39962 +г. Заинск,55.2988956,52.0063163,39739 +г. Шебекино,50.4004378,36.8878943,39680 +г. Тутаев,57.8674415,39.536868,39643 +г. Баксан,43.6819288,43.5344884,39593 +г. Абинск,44.8679116,38.1617987,39511 +г. Кольчугино,56.3328004,39.391268,39410 +г. Стрежевой,60.7327472,77.6039789,39169 +г. Моршанск,53.4436449,41.8115193,39023 +г. Советск,55.0811102,21.8887115,38910 +г. Ялуторовск,56.6546647,66.3121926,38853 +г. Новозыбков,52.5371414,31.9357361,38680 +г. Изобильный,45.3684383,41.7085873,38614 +г. Амурск,50.2345703,136.8791531,38606 +г. Волхов,59.9004589,32.3520685,38511 +г. Тулун,54.5570223,100.5779905,38440 +г. Луга,58.735207,29.847945,38407 +г. Сафоново,55.1200105,33.233658,38403 +г. Кизилюрт,43.2038278,46.872864,38335 +г. Югорск,61.3124125,63.3364948,38238 +г. Шатура,55.5778265,39.5445373,38230 +г. Ртищево,52.2616938,43.7842747,37850 +г. Переславль-Залесский,56.7360013,38.8543687,37738 +г. Протвино,54.8705841,37.2182922,37735 +г. Южноуральск,54.4490432,61.2581713,37478 +г. Истра,55.9061876,36.8600649,37474 +г. Качканар,58.7050979,59.4839558,37307 +г. Красноуфимск,56.612429,57.7635494,37301 +г. Коркино,54.8903864,61.4032939,37224 +г. Джанкой,45.7092913,34.3883718,37014 +г. Ирбит,57.683808,63.0576929,37009 +пгт Маркова рп,52.211106,104.207909,36971 +г. Мценск,53.2789769,36.5749963,36960 +г. Усть-Кут,56.780878,105.745373,36918 +г. Моздок,43.7472597,44.657072,36784 +г. Заволжье,56.6404919,43.3870929,36763 +г. Кинель,53.2209314,50.6343567,36729 +г. Урюпинск,50.7904909,42.0289034,36669 +г. Реж,57.3716798,61.38338,36585 +г. Алексеевка,50.6299988,38.6881066,36578 +станица Динская,45.2362774,39.2405427,36576 +г. Ефремов,53.137603,38.117673,36545 +г. Малгобек,43.5097018,44.5901112,36480 +г. Елизово,53.1829398,158.3884312,36240 +г. Вязники,56.2977573,42.268676,36203 +г. Алапаевск,57.8476947,61.6695786,36189 +г. Учалы,54.3066963,59.4127255,36175 +г. Черняховск,54.6245018,21.7969164,36128 +г. Кыштым,55.706159,60.5562529,36045 +пгт Горячеводский рп,44.0236208,43.0973777,36032 +г. Беслан,43.1936637,44.533792,35929 +Балаклава,44.501414,33.600037,35919 +г. Людиново,53.8701272,34.4385772,35874 +г. Звенигород,55.7295881,36.8553623,35842 +г. Спасск-Дальний,44.5900901,132.8158275,35732 +г. Светлоград,45.3286594,42.856594,35703 +г. Красный Сулин,47.883196,40.0781926,35697 +г. Фролово,49.7648209,43.6649431,35661 +г. Ахтубинск,48.2753708,46.1905298,35635 +г. Саянск,54.1108195,102.1802309,35561 +станица Ленинградская,46.3449638,39.3907816,35561 +г. Апрелевка,55.527617,37.0650837,35514 +г. Благовещенск,55.0498049,55.9553149,35481 +г. Лесозаводск,45.4780131,133.4185314,35433 +г. Печора,65.1486942,57.2239645,35254 +г. Богородск,56.1020008,43.5135913,35068 +г. Миллерово,48.9259954,40.3982659,34841 +г. Азнакаево,54.8597519,53.0744925,34750 +г. Сокол,59.4757853,40.1114848,34742 +деревня Ватутинки,55.4942411,37.3288668,34697 +г. Сланцы,59.1177053,28.0882334,34628 +г. Коряжма,61.2886248,47.1002365,34523 +г. Тайшет,55.9405482,98.0030449,34491 +г. Ликино-Дулёво,55.7077293,38.9577959,34191 +г. Тосно,59.540686,30.8777641,34066 +г. Мирный,62.5362564,113.9667642,34045 +г. Новокубанск,45.1036986,41.0475442,34000 +г. Нурлат,54.4281036,50.8049432,33990 +г. Шарыпово,55.5391274,89.1801041,33961 +г. Корсаков,46.6324255,142.7994957,33950 +г. Можайск,55.5069403,36.0239829,33880 +г. Партизанск,43.1504279,133.1666126,33832 +г. Дальнегорск,44.5541197,135.566156,33655 +г. Конаково,56.7275398,36.801348,33560 +г. Каменка,53.1855489,44.0468101,33491 +г. Гулькевичи,45.3605339,40.6918433,33357 +г. Новодвинск,64.4136473,40.8206783,33294 +г. Гай,51.4650759,58.4436431,33280 +г. Губкинский,64.4456403,76.4713798,33273 +деревня Рассказовка,55.6317853,37.3132339,33259 +г. Нарткала,43.5578132,43.8576082,33203 +г. Зеленокумск,44.4032361,43.8841172,33187 +пгт Приволжский рп,51.4109503,46.0481131,33096 +г. Валуйки,50.211172,38.0999436,33032 +г. Чернушка,56.515934,56.0764463,32991 +г. Тавда,58.0434995,65.274369,32749 +г. Сухой Лог,56.9074957,62.0357985,32748 +г. Углич,57.522461,38.3018763,32719 +г. Трехгорный,54.8177944,58.4463721,32463 +г. Камень-на-Оби,53.7914749,81.3545962,32385 +г. Алатырь,54.8372699,46.5339898,32265 +г. Кулебаки,55.4296716,42.5124575,32184 +г. Усинск,65.9940586,57.5569288,32182 +г. Острогожск,50.867943,39.0406177,31699 +станица Новотитаровская,45.2376345,38.9765189,31520 +г. Дагестанские Огни,42.1152854,48.193977,31412 +г. Алушта,44.6763996,34.4100439,31364 +г. Тейково,56.8542792,40.5353799,31305 +г. Дюртюли,55.4848147,54.8524883,31185 +село Иглино,54.834468,56.416165,31169 +г. Советский,61.3707009,63.5667177,31138 +г. Усть-Джегута,44.0838556,41.9710356,31137 +г. Приморско-Ахтарск,46.0515858,38.1704382,31087 +Фактория,64.53939,40.5170011,31008 +г. Кохма,56.9325054,41.0931324,30940 +г. Благодарный,45.098943,43.4306154,30827 +село Ачхой-Мартан,43.1872011,45.2863481,30739 +г. Дедовск,55.8704582,37.124447,30731 +г. Вичуга,57.2044884,41.9131422,30694 +город Нововоронеж,51.3091935,39.216289,30658 +г. Зима,53.9336544,102.0498973,30640 +станица Кущевская,46.569894,39.619836,30375 +г. Обь,54.9945378,82.6937661,30369 +станица Староминская,46.5331093,39.0535727,30362 +пгт Томилино рп,55.663107,37.949918,30306 +г. Сердобск,52.4697777,44.2123029,30220 +г. Богданович,56.7764214,62.0462888,30142 +г. Нижнеудинск,54.896942,99.031408,29995 +г. Электрогорск,55.8778372,38.7805887,29982 +г. Луховицы,54.7659596,39.2706433,29889 +г. Вятские Поляны,56.2285162,51.0616058,29742 +г. Фурманов,57.2537548,41.1054731,29715 +г. Борзя,50.3877136,116.5235118,29596 +г. Богородицк,53.7700594,38.1225087,29560 +станица Павловская,46.122016,39.781416,29514 +г. Гусев,54.5915197,22.1942896,29234 +г. Муравленко,63.795443,74.494826,29233 +г. Слободской,58.7312106,50.1669806,29148 +г. Кандалакша,67.1566641,32.4142961,29138 +пгт Краснообск рп,54.921237,82.991197,29086 +пгт Дрожжино рп,55.5277293,37.5937701,29072 +г. Балабаново,55.1774068,36.656839,29029 +г. Лосино-Петровский,55.869566,38.202852,29000 +г. Артемовский,57.3384593,61.8945883,28943 +г. Добрянка,58.542592,56.293958,28782 +г. Маркс,51.7133247,46.7400877,28749 +г. Великий Устюг,60.7602824,46.3053948,28670 +г. Городец,56.644865,43.4722664,28660 +г. Тында,55.1546593,124.7468001,28625 +г. Бахчисарай,44.751299,33.8750748,28609 +г. Сорочинск,52.4266473,53.1541824,28478 +г. Касимов,54.9373071,41.3913313,28443 +г. Кудымкар,59.0168409,54.6573613,28293 +пгт Власиха,55.680815,37.1902369,28240 +пгт Разумное,50.533611,36.689562,28192 +г. Ростов,57.2050397,39.4378513,28122 +г. Заречный,56.8103256,61.3380277,28112 +г. Киров,54.0789799,34.3076309,28097 +город Семилуки,51.6951946,39.0188991,27938 +г. Славгород,52.999413,78.6458451,27900 +г. Аша,54.990582,57.2784381,27890 +пгт Энем,44.9263995,38.9107709,27717 +г. Барабинск,55.3515169,78.3464604,27648 +г. Еманжелинск,54.7554485,61.3243638,27632 +посёлок Придорожный,53.0860041,50.1587223,27515 +пгт Иноземцево кп,44.0970899,43.0894193,27500 +г. Старая Русса,57.9907473,31.355452,27487 +г. Дивногорск,55.9577356,92.380129,27477 +г. Похвистнево,53.6497658,52.1234466,27333 +г. Киржач,56.1486461,38.8635967,27318 +пгт Красково дп,55.65879,37.9885476,27306 +г. Кушва,58.2825138,59.7647615,27306 +г. Мирный,62.764551,40.336094,27262 +г. Кировск,59.875234,30.9815172,27238 +село Экажево,43.2082923,44.8190051,27224 +г. Топки,55.2765207,85.6152094,27158 +г. Камышлов,56.8464908,62.7120309,27117 +г. Карталы,53.0537382,60.6477347,27103 +г. Заводоуковск,56.5028398,66.5513555,27100 +деревня Мисайлово,55.5639995,37.8255811,27093 +деревня Путилково,55.865253,37.392526,27081 +станица Северская,44.8562413,38.6959282,26973 +г. Тара,56.9159295,74.3648797,26878 +село Засечное,53.105904,45.0717034,26878 +г. Шумерля,55.5229338,46.3752894,26873 +г. Балтийск,54.6513858,19.9140642,26796 +г. Новоалександровск,45.4932983,41.2153595,26767 +г. Гурьевск,54.7705454,20.6039948,26760 +г. Котовск,52.5923425,41.5102238,26694 +село Кочубеевское,44.6907487,41.8242914,26645 +г. Майский,43.6283265,44.051839,26632 +г. Кувандык,51.4785827,57.3610986,26596 +г. Гагарин,55.5526733,34.9950319,26500 +г. Красноармейск,56.105426,38.140838,26492 +г. Кимовск,53.9698013,38.538127,26475 +г. Волоколамск,56.0356464,35.958479,26389 +г. Петровск,52.3094724,45.3851898,26319 +г. Соль-Илецк,51.1634754,54.9895396,26149 +г. Ипатово,45.7181195,42.8970759,26122 +г. Костомукша,64.5890912,30.6015362,26048 +пгт Малаховка рп,55.6452616,38.0042385,25989 +г. Удомля,57.8787641,35.0166208,25950 +г. Янаул,56.2649073,54.9297772,25908 +г. Карпинск,59.766559,60.0012125,25879 +г. Кондопога,62.2059903,34.2681816,25851 +г. Коммунар,59.6215741,30.3935534,25793 +г. Отрадное,59.7726485,30.798845,25706 +г. Холмск,47.0408656,142.0416132,25677 +станица Тбилисская,45.3644521,40.2016871,25650 +г. Полысаево,54.6054908,86.2809963,25631 +г. Красноперекопск,45.9536596,33.792071,25569 +г. Киреевск,53.9320407,37.9219941,25560 +пгт Мостовской,44.4144395,40.790292,25548 +г. Лабытнанги,66.6593565,66.3881811,25501 +село Александровское,44.7105748,43.0049484,25479 +город Десногорск,54.1463618,33.2834089,25414 +г. Алейск,52.4922482,82.7795177,25380 +г. Десногорск,54.1463618,33.2834089,25345 +г. Дятьково,53.5958143,34.355106,25255 +г. Скопин,53.8235282,39.5493392,25238 +пгт Калининец рп,55.559738,36.981914,25082 +г. Семенов,56.7890706,44.4902872,25075 +пгт Ильский,44.804549,38.546089,24932 +г. Асино,56.990811,86.1764966,24913 +г. Карасук,53.7343642,78.0422879,24890 +г. Кировск,67.6151587,33.6636568,24857 +станица Ессентукская,44.0267307,42.8764379,24710 +пгт Октябрьский рп,55.6110724,37.9737423,24704 +г. Знаменск,48.5866454,45.7369007,24628 +г. Гусиноозерск,51.2865987,106.5229836,24451 +пгт Пойковский,60.996548,71.902431,24440 +г. Североуральск,60.1533388,59.952553,24428 +г. Бутурлиновка,50.8312775,40.5977424,24397 +г. Озёры,54.8540209,38.5598706,24359 +г. Саки,45.13433,33.6032255,24285 +г. Калач-на-Дону,48.6889101,43.5307585,24277 +г. Унеча,52.8461971,32.6757398,24274 +г. Морозовск,48.351132,41.8307844,24258 +г. Северобайкальск,55.6355591,109.3361645,24233 +г. Советская Гавань,48.9663668,140.2852088,24231 +станица Полтавская,45.3654401,38.2109117,24164 +г. Родники,57.1024811,41.7298234,24101 +г. Зерноград,46.849613,40.3128993,24076 +пгт Северный,50.6774988,36.5607698,24070 +деревня Новое Девяткино,60.0572998,30.4762703,23988 +посёлок Тельмана,59.725444,30.612106,23986 +г. Карачаевск,43.7731804,41.9144084,23867 +станица Елизаветинская,45.0484348,38.7999276,23841 +г. Строитель,50.785172,36.486998,23780 +г. Татарск,55.2144722,75.9740764,23711 +г. Медногорск,51.4038655,57.5831571,23693 +пгт Федоровский,61.6484245,73.488652,23614 +г. Дальнереченск,45.9308807,133.7316844,23613 +пгт Афипский,44.9034044,38.8411512,23592 +г. Уварово,51.983084,42.261,23584 +г. Сегежа,63.7437691,34.3126737,23543 +г Курчалой,43.2045354,46.0889297,23425 +г. Нарьян-Мар,67.6379742,53.0069529,23399 +г. Губаха,58.8370347,57.5544775,23397 +г. Среднеуральск,56.9919113,60.4771159,23344 +г. Кубинка,55.6790296,37.2635177,23146 +г. Нефтекумск,44.7545311,44.9865999,23137 +станица Троицкая,43.3060175,44.9893927,23078 +пгт Свердловский рп,55.9032059,38.1361082,23058 +станица Отрадная,44.39317,41.5156681,23041 +г. Верхний Уфалей,56.0487398,60.2320146,22981 +пгт Городище рп,48.8096322,44.4761656,22905 +г. Старая Купавна,55.810648,38.175624,22898 +г. Менделеевск,55.8951887,52.3143634,22875 +г. Железноводск,44.1320536,43.0304695,22863 +г. Голицыно,55.6189919,36.9856491,22733 +г. Аткарск,51.8737167,45.000324,22709 +пгт Тучково рп,55.6007848,36.4718788,22657 +рп Чишмы,54.5892603,55.3803504,22597 +г. Лермонтов,44.1053341,42.9731493,22444 +посёлок Бугры,60.0700161,30.3997764,22428 +город Павловск,50.4533503,40.1369424,22384 +г. Тайга,56.1723887,85.4268959,22375 +г. Никольское,59.7042138,30.7874065,22355 +г. Верещагино,58.0798499,54.6579923,22239 +г. Сосногорск,63.599118,53.8762442,22189 +г. Гурьевск,54.2859162,85.9477116,22134 +г. Хадыженск,44.412253,39.5320316,22094 +г. Невьянск,57.4912147,60.218324,22061 +г. Тырныауз,43.3981998,42.9214143,22056 +г. Котельниково,47.6310339,43.1330384,22016 +г. Таштагол,52.7594115,87.8476574,21980 +г. Давлеканово,54.222692,55.0311854,21834 +г. Бронницы,55.4254542,38.264161,21831 +г. Вилючинск,52.9302624,158.4057425,21774 +г. Калтан,53.521076,87.2771909,21752 +пгт Медведево,56.6332603,47.8032407,21752 +г. Вихоревка,56.1208112,101.1704184,21719 +г. Семикаракорск,47.517792,40.811485,21719 +г. Лысково,56.0262601,45.0357974,21657 +г. Сасово,54.3508047,41.9117508,21628 +г. Бавлы,54.4063524,53.2458119,21628 +г. Железногорск-Илимский,56.5847582,104.1142358,21621 +г. Вельск,61.0658321,42.1032464,21613 +г. Алдан,58.6095359,125.3817685,21590 +пгт Стройкерамика,53.2766484,50.3870415,21567 +г. Алагир,43.0416623,44.2197807,21550 +пгт Ахтырский,44.8503138,38.2998264,21515 +г. Красноуральск,58.3486753,60.0408929,21507 +г. Бежецк,57.7859527,36.6905192,21466 +г. Усть-Катав,54.9260247,58.1528932,21439 +г. Оленегорск,68.1420962,33.2669298,21438 +г. Рошаль,55.6632087,39.8656345,21401 +г. Ленск,60.7276227,114.9548502,21392 +пгт Излучинск,60.9530651,76.891202,21389 +г. Калачинск,55.059708,74.5655042,21378 +г. Красноармейск,51.0235479,45.6951366,21350 +г. Светлый,54.6773492,20.1356707,21114 +г. Рыбное,54.7256308,39.5135902,21069 +г. Котово,50.3205819,44.803057,21028 +г. Остров,57.3452065,28.3437983,20923 +г. Бобров,51.0902207,40.031849,20871 +пгт Кольцово рп,54.939754,83.189226,20862 +село Дыгулыбгей,43.6605157,43.5399799,20852 +г. Колпашево,58.3114151,82.9027717,20824 +г. Новопавловск,43.957372,43.631908,20781 +г. Тогучин,55.2251228,84.4103609,20766 +г. Чегем,43.567119,43.5866245,20736 +г. Зарайск,54.7624731,38.8851435,20736 +село Карабудахкент,42.7101719,47.5652001,20710 +г. Октябрьск,53.1641278,48.6707034,20703 +г. Армянск,46.1058917,33.6911918,20692 +г. Ряжск,53.7068457,40.0521364,20634 +г. Сысерть,56.5005302,60.8190383,20634 +г. Буй,58.4733865,41.5306164,20564 +пгт Безенчук,52.9844016,49.4332576,20516 +г. Исилькуль,54.9095226,71.2815165,20515 +г. Хотьково,56.2515987,37.9394556,20466 +г. Шарья,58.3760015,45.4060912,20439 +г. Нижний Ломов,53.5301144,43.6730824,20421 +г. Арск,56.0913566,49.8769472,20421 +г. Пикалево,59.5131477,34.1772986,20388 +г. Оха,53.5868177,142.9412704,20357 +пгт Монино рп,55.8393791,38.1953929,20313 +г. Инта,66.0367224,60.1153645,20271 +г. Сергач,55.5200817,45.4813786,20256 +г. Бологое,57.8855456,34.0537078,20234 +г. Котельнич,58.3034526,48.3475879,20144 +г. Лебедянь,53.0155445,39.143535,20049 +станица Зеленчукская,43.8608392,41.5827377,20009 +г. Белоярский,63.7120526,66.6773163,19994 +г. Агрыз,56.5234282,52.9943111,19991 +г. Нерехта,57.4543591,40.5725027,19977 +пгт Боровский рп,57.0437279,65.7219998,19972 +г. Буинск,54.964071,48.2901712,19968 +станица Выселки,45.5801087,39.6553854,19955 +г. Терек,43.4837944,44.140333,19948 +село Новая Усмань (часть 2),51.6440564,39.4129162,19939 +г. Черепаново,54.2206618,83.3724671,19900 +г. Тарко-Сале,64.9117423,77.7610229,19900 +г. Никольск,53.7138244,46.0799725,19873 +г. Куровское,55.5790488,38.920837,19857 +г. Ковылкино,54.0391206,43.9191408,19793 +г. Козьмодемьянск,56.3333702,46.5465866,19731 +г. Данков,53.2576888,39.1456386,19726 +г. Фокино,42.9707585,132.4110104,19711 +пгт Каа-Хем,51.6974519,94.559472,19686 +г. Усмань,52.0444077,39.7263813,19662 +посёлок Строитель,52.6512001,41.4310661,19647 +г. Омутнинск,58.6698906,52.189375,19629 +рп Приютово,53.8951581,53.9369819,19595 +село Чалтырь,47.2826729,39.4992447,19583 +г. Пущино,54.8351813,37.6265045,19578 +г. Дудинка,69.4032072,86.1909075,19556 +поселок Трудовое,43.3002872,132.0632507,19543 +г. Черноголовка,56.0099863,38.3792964,19530 +г. Оса,57.2889708,55.468868,19523 +пгт Кокошкино дп,55.598467,37.167633,19490 +пгт Промышленная,54.916573,85.6376222,19484 +пгт Ленинкент,42.9703441,47.3535191,19438 +поселок Ойсхара,43.2627893,46.2498555,19415 +г. Зея,53.7340347,127.2657094,19414 +станица Суворовская,44.1975139,42.6499527,19378 +г. Зверево,48.0434167,40.1265252,19353 +поселок Игра,57.5401354,53.0861913,19319 +село Гойты,43.1609736,45.6212637,19198 +станица Брюховецкая,45.8020888,38.9971898,19154 +станица Незлобная,44.1168985,43.408563,19068 +пгт Березовка,56.037108,93.1266,19059 +поселок Ува,56.9820545,52.1873031,19057 +г. Арамиль,56.6915504,60.8441135,19013 +г. Пролетарск,46.7038132,41.7276002,18983 +г. Ардон,43.1755904,44.2956828,18956 +г. Лодейное Поле,60.7320844,33.5522164,18905 +посёлок Саракташ,51.7830951,56.3652582,18789 +г. Приозерск,61.03598,30.115586,18777 +станица Холмская,44.848128,38.3892456,18699 +г. Кировград,57.4298874,60.0624019,18698 +село Раевский,54.0650359,54.932837,18698 +г. Николаевск-на-Амуре,53.1461923,140.7110577,18631 +г. Нелидово,56.223391,32.7766208,18603 +пгт Свободы рп,44.0248348,43.0514483,18582 +станица Новопокровская,45.9538509,40.7070143,18559 +село Чигири,50.3391503,127.5076851,18538 +г. Харабали,47.4089236,47.2525264,18514 +г. Няндома,61.6654144,40.2063093,18473 +село Автуры,43.163267,46.0031899,18446 +г. Нижняя Тура,58.6310449,59.8520228,18392 +г. Пласт,54.3691735,60.815252,18379 +г. Новый Оскол,50.764439,37.863064,18359 +пгт Тарки,42.9445024,47.4957949,18233 +г. Суровикино,48.6189098,42.8542126,18227 +г. Боготол,56.2098683,89.5300867,18206 +рп Южный,53.2513304,83.6947313,18098 +г. Ершов,51.35079,48.2763191,18095 +г. Нефтегорск,52.79725,51.1638245,18076 +пгт Тальменка рп,53.8172662,83.5691716,18070 +г. Слюдянка,51.6563035,103.7186495,18058 +село Бабаюрт,43.6011227,46.7793044,18039 +станица Нестеровская,43.2381741,45.0491681,17981 +г. Электроугли,55.7170793,38.219367,17944 +г. Кукмор,56.1860939,50.8971592,17886 +г. Кяхта,50.3466144,106.453365,17877 +пгт Удельная дп,55.6349087,38.049353,17846 +г. Судак,44.8505071,34.9761502,17834 +г. Баймак,52.5913527,58.3111821,17833 +пгт Линево рп,54.4570315,83.3815692,17779 +посёлок завода Мосрентген,55.620947,37.473815,17758 +г. Покров,55.9167157,39.1733602,17747 +село Высокая Гора,55.912126,49.312767,17736 +г. Стародуб,52.5853129,32.7603416,17687 +г. Жуковка,53.5340871,33.7302336,17628 +г. Шахунья,57.6763123,46.6128512,17626 +г. Калач,50.4240228,41.0162465,17624 +г. Суворов,54.122088,36.490348,17598 +посёлок ВНИИССОК,55.6569429,37.2117743,17597 +г. Радужный,55.9960812,40.3322223,17569 +г. Льгов,51.65971,35.261144,17557 +г. Енисейск,58.4485678,92.1650748,17537 +село Белая Глина,46.0736706,40.8713114,17470 +г. Карачев,53.1296862,34.9887384,17449 +г. Белогорск,45.0570816,34.599941,17445 +г. Собинка,55.9938217,40.0178919,17444 +пгт Лучегорск,46.438443,134.289358,17437 +станица Медведовская,45.4491448,39.0101617,17404 +пгт Ванино,49.0909744,140.2563927,17326 +г. Талдом,56.7308601,37.5276018,17317 +пгт Васильево,55.8369276,48.7040265,17286 +г. Юрьев-Польский,56.4936868,39.6680526,17276 +г. Абдулино,53.6778052,53.6473384,17274 +станица Старощербиновская,46.6297567,38.6673969,17251 +г. Константиновск,47.5773447,41.0967357,17207 +село Бачи-Юрт,43.2209854,46.194994,17173 +г. Куса,55.3386556,59.4386134,17136 +пгт Коченево рп,55.019014,82.2060574,17053 +село Осиново,55.8775039,48.8897995,16991 +село Нижнее Казанище,42.760984,47.161627,16984 +г. Онега,63.9162842,38.0805165,16947 +г. Новомичуринск,54.037654,39.7466785,16900 +г. Плавск,53.7095277,37.2862058,16893 +село Майма,52.0037707,85.8962579,16890 +село Цоци-Юрт,43.2426159,46.0018219,16890 +пгт Янино-1,59.945394,30.5611967,16886 +деревня Сапроново,55.529323,37.712318,16817 +деревня Пыхтино,55.6209417,37.3002729,16803 +село Кантышево,43.2281058,44.6484198,16783 +г. Козельск,54.0348045,35.7806829,16759 +село Краснокумское,44.1748104,43.4967116,16702 +г. Нытва,57.9336576,55.3355911,16675 +г. Осташков,57.1457822,33.1116377,16674 +село Кинель-Черкассы,53.4640756,51.5193824,16658 +г. Зеленоградск,54.9599261,20.4752742,16625 +село Новая Усмань (часть 1),51.6440564,39.4129162,16601 +пгт Шушенское,53.333753,91.935624,16573 +г. Туринск,58.0394946,63.6981776,16561 +г. Краснослободск,48.7068501,44.5631832,16545 +пгт Агинское,51.1036078,114.5378536,16511 +г. Нижняя Салда,58.0749078,60.7025219,16505 +г. Шимановск,52.005177,127.7005913,16488 +село Плиево,43.2854671,44.8359413,16440 +станица Гостагаевская,44.8948984,37.3162896,16438 +г. Яровое,52.9252719,78.5729219,16424 +город Поворино,51.195289,42.2473555,16417 +г. Бакал,54.9406707,58.8051112,16345 +г. Инза,53.8549261,46.353359,16293 +г. Шумиха,55.2281331,63.2901783,16264 +пгт Шексна,59.2361104,38.5112653,16246 +г. Бикин,46.8185692,134.2550619,16240 +г. Жуков,55.0302319,36.7393387,16224 +г. Светлогорск,54.9439073,20.1514612,16207 +г. Бокситогорск,59.473579,33.8457452,16185 +г. Кирсанов,52.6506577,42.7284824,16164 +пгт Рощино,60.2408076,29.6288048,16162 +г. Камызяк,46.1106454,48.0732549,16154 +пгт Белый Яр,61.260563,73.252472,16141 +пгт им. Воровского рп,55.7219506,38.3276944,16127 +г. Подпорожье,60.912778,34.1567171,16123 +посёлок Дубовое,50.5303214,36.5682872,16101 +г. Гаврилов-Ям,57.3091517,39.8544895,16084 +село Нартан,43.5054195,43.7016693,16075 +г. Покачи,61.7422837,75.5940895,16040 +г. Поронайск,49.2387506,143.1008839,16026 +г. Руза,55.7015428,36.1959789,16014 +г. Мензелинск,55.7270085,53.1005154,16008 +деревня Куюки,55.7128384,49.3565309,15977 +г. Иланский,56.2375329,96.0673849,15945 +посёлок Орловский,46.874451,42.05931,15942 +село Каякент,42.3862993,47.9054979,15923 +г. Сельцо,53.3739073,34.106007,15906 +станица Раевская,44.836305,37.5496436,15902 +село Учкекен,43.9390432,42.5155851,15849 +г. Райчихинск,49.7941325,129.411213,15797 +г. Ковдор,67.5662699,30.4741763,15770 +деревня Островцы,55.5912674,37.9926244,15752 +село Супсех,44.8948984,37.3162896,15736 +г. Кондрово,54.7959825,35.9275777,15734 +г. Мамадыш,55.7150947,51.4128069,15726 +г. Межгорье,54.2396811,57.9612743,15697 +посёлок Зимовники,47.1453719,42.4676643,15691 +пгт Емельяново,56.1686437,92.6866976,15649 +г. Болотное,55.6692803,84.3906602,15644 +г. Кизел,59.0512352,57.6471132,15619 +пгт Товарково,54.67724,35.942735,15606 +село Поселье,51.8057402,107.5376329,15603 +станица Анапская,44.8948984,37.3162896,15593 +пгт Семендер,42.9911799,47.4021163,15565 +пгт Кратово дп,55.5973949,38.1635172,15565 +г. Жирновск,50.9769212,44.7857873,15555 +посёлок Навля,52.8301087,34.5066338,15536 +пгт Заводской,43.1077853,44.6453692,15508 +г. Дегтярск,56.7048,60.0790826,15497 +г. Свирск,53.0838888,103.3413682,15485 +пгт Сузун рп,53.7891996,82.3161043,15482 +г. Ясный,51.0368874,59.8742748,15471 +село Подстепки,53.5179261,49.1533951,15455 +посёлок Зональная Станция,56.4268771,85.0227819,15421 +станица Варениковская,45.1198484,37.6385129,15385 +г. Касли,55.8869825,60.7422584,15383 +посёлок Усть-Ордынский,52.8052189,104.7536738,15364 +село Гехи,43.1606137,45.4742778,15352 +г. Новоаннинский,50.5295721,42.6666194,15351 +пгт Анна,51.489329,40.4242248,15316 +"посёлок подсобного хозяйства ""Воскресенское""",55.5296175,37.4458356,15293 +г. Нерчинск,51.9594649,116.5853127,15290 +село Ахты,41.4591981,47.7495262,15285 +г. Магас,43.1686871,44.8131101,15271 +г. Ясногорск,54.4794749,37.689663,15269 +г. Новоузенск,50.4551199,48.1411389,15216 +посёлок Знамя Октября,55.47574,37.538359,15199 +село Катар-Юрт,43.1688806,45.370387,15199 +пгт Запрудня рп,56.5609117,37.4336132,15189 +г. Бородино,55.9053464,94.9022323,15174 +пгт Рефтинский,57.0906513,61.6564554,15164 +пгт Софрино рп,56.1354141,37.9260237,15136 +пгт Вырица,59.4172905,30.3469408,15086 +г. Рыльск,51.568137,34.6802211,15069 +г. Купино,54.3661206,77.2973372,15065 +село Хомутово,52.4652523,104.3620353,15064 +пгт Большие Вязёмы рп,55.6291397,37.0053667,15060 +г. Петровск-Забайкальский,51.2748412,108.8468131,15015 +г. Почеп,52.9153976,33.4745131,14991 +г. Палласовка,50.0502023,46.8804085,14966 +г. Калининск,51.4993043,44.4710883,14949 +г. Щигры,51.8785827,36.8911689,14927 +г. Барыш,53.6534032,47.1180501,14924 +пгт Чернянка,50.940917,37.804134,14896 +г. Сортавала,61.7032224,30.6917823,14867 +пгт Грибановский,51.4564459,41.9799021,14830 +станица Васюринская,45.1181463,39.4216389,14829 +г. Талица,57.0123163,63.7320587,14808 +г. Сухиничи,54.0973084,35.344484,14806 +г. Куртамыш,54.9369493,64.4203207,14806 +г. Заполярный,69.4131822,30.7985579,14791 +посёлок Развилка,55.5910519,37.7529499,14788 +г. Дубовка,49.0554351,44.8269342,14779 +пгт Лесной Городок дп,55.636239,37.212612,14765 +г. Белокуриха,51.9961123,84.9839441,14735 +г. Цимлянск,47.6477932,42.092975,14731 +село Кулунда,52.5661304,78.9368917,14708 +пгт Новый Городок,54.3036194,86.2934438,14691 +г. Навашино,55.5438077,42.1887675,14664 +г. Катав-Ивановск,54.7520677,58.1984888,14663 +пгт Ильинский рп,55.6202604,38.1055975,14645 +г. Краснозаводск,56.4409201,38.2320198,14639 +деревня Кондратово,57.9760676,56.1090821,14631 +г. Советск,57.5841376,48.9589455,14626 +станица Егорлыкская,46.553251,40.683235,14602 +село Кулешовка,47.0857816,39.5270717,14568 +пгт Селятино рп,55.5141029,36.9798359,14523 +г. Грязовец,58.875883,40.2485948,14505 +г. Красновишерск,60.3903039,57.0535948,14460 +поселок Балезино,57.983878,53.012307,14459 +станица Гиагинская,44.8847971,40.0577305,14445 +село Алхан-Кала,43.2624396,45.534823,14423 +г. Очер,57.8852534,54.7161526,14385 +город Богучар,49.93528,40.5591512,14370 +г. Волгореченск,57.4424513,41.1592512,14355 +село Донское,45.4672559,41.989783,14338 +г. Приволжск,57.380718,41.2807571,14332 +станица Старовеличковская,45.4329681,38.7244163,14310 +г. Ивдель,60.6945985,60.4245258,14306 +г. Чудово,59.1248174,31.6866267,14302 +г. Красный Кут,50.9597049,46.9711885,14296 +г. Яранск,57.3041231,47.8478976,14284 +село Старые-Атаги,43.1229624,45.7414172,14280 +пгт Средняя Ахтуба рп,48.7136601,44.8600821,14241 +г. Агидель,55.8997421,53.9221357,14219 +посёлок Нижнесортымский,62.4428117,71.7652884,14217 +рп Усть-Абакан,53.8329508,91.3943386,14210 +село Красногвардейское,45.8450489,41.5144643,14200 +село Новый Хушет,42.8993406,47.5613354,14180 +г. Полярные Зори,67.3738152,32.4891688,14146 +посёлок Майский,50.5218213,36.4544411,14143 +г. Ужур,55.3142192,89.8334338,14134 +г. Шлиссельбург,59.9443081,31.0332835,14131 +г. Гвардейск,54.6588822,21.0500744,14122 +станица Калининская,45.4855794,38.6616721,14121 +г. Кашин,57.3600935,37.6118448,14113 diff --git a/src/index.html b/src/index.html new file mode 100644 index 00000000..83427f8c --- /dev/null +++ b/src/index.html @@ -0,0 +1,12 @@ + + + + + + Прогноз погоды + + + + + + \ No newline at end of file diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 00000000..8a288e07 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,9 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { provideHttpClient } from '@angular/common/http'; +import { AppComponent } from './app/app'; + +bootstrapApplication(AppComponent, { + providers: [ + provideHttpClient() + ] +}).catch((err) => console.error(err)); \ No newline at end of file diff --git a/src/styles.css b/src/styles.css new file mode 100644 index 00000000..9edf5459 --- /dev/null +++ b/src/styles.css @@ -0,0 +1,33 @@ +* { + scrollbar-width: thin; + scrollbar-color: #3a5a8c #0f1629; +} + +*::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +*::-webkit-scrollbar-track { + background: #0f1629; + border-radius: 10px; +} + +*::-webkit-scrollbar-thumb { + background: #3a5a8c; + border-radius: 10px; +} + +*::-webkit-scrollbar-thumb:hover { + background: #5a7ab0; +} + +*:focus { + outline: none; + box-shadow: 0 0 0 2px rgba(90, 150, 220, 0.5); +} + +body { + background: radial-gradient(circle at 20% 30%, #0a0f1e, #05070f); + color: #eef5ff; +} \ No newline at end of file diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 00000000..5a2cc466 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,21 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [], + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "rootDir": "./src" + }, + "files": [ + "src/main.ts" + ], + "include": [ + "src/**/*.d.ts" + ], + "exclude": [ + "src/**/*.spec.ts" + ] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..2ab74427 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,33 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "compileOnSave": false, + "compilerOptions": { + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "isolatedModules": true, + "experimentalDecorators": true, + "importHelpers": true, + "target": "ES2022", + "module": "preserve" + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + }, + "files": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/tsconfig.spec.json b/tsconfig.spec.json new file mode 100644 index 00000000..ef5434c1 --- /dev/null +++ b/tsconfig.spec.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine" + ], + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "rootDir": "./src" + }, + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} \ No newline at end of file