maplibre-preview 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile ADDED
@@ -0,0 +1,50 @@
1
+ require 'rspec/core/rake_task'
2
+ require_relative 'lib/maplibre-preview/version'
3
+
4
+ rspec = RSpec::Core::RakeTask.new(:spec)
5
+
6
+ require 'rubocop/rake_task'
7
+
8
+ RuboCop::RakeTask.new
9
+
10
+
11
+ task default: %i[rspec]
12
+
13
+ desc 'CI Rspec run with reports'
14
+ task :rspec do |t|
15
+ # rm "coverage.data" if File.exist?("coverage.data")
16
+ rspec.rspec_opts = '--profile --color -f documentation -f RspecJunitFormatter --out ./results/rspec.xml'
17
+ Rake::Task['spec'].invoke
18
+ end
19
+
20
+ require 'erb'
21
+
22
+ desc 'Update readme'
23
+ task :readme do |t|
24
+ puts 'Update readme.erb -> readme.md'
25
+ template = File.read './README.erb'
26
+ renderer = ERB.new template, trim_mode: '-'
27
+ File.write './README.md', renderer.result
28
+ end
29
+
30
+ desc 'Pre commit'
31
+ task commit: %i[spec readme]
32
+
33
+ desc 'Build'
34
+ task build: %i[readme] do |t|
35
+ puts 'Build'
36
+ gemspec = Dir['*.gemspec'].first
37
+ system "gem build #{gemspec}" or exit 1
38
+ end
39
+
40
+ desc 'Build&push new version'
41
+ task push: %i[spec] do |t|
42
+ puts 'Build&push new version'
43
+ gemspec = Dir['*.gemspec'].first
44
+ system "gem build #{gemspec}" or exit 1
45
+ system "gem install ./maplibre-preview-#{MapLibrePreview::VERSION}.gem" or exit 1
46
+ # curl -u gempusher https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
47
+ system "gem push maplibre-preview-#{MapLibrePreview::VERSION}.gem" or exit 1
48
+ system 'gem list -r maplibre-preview' or exit 1
49
+ end
50
+
data/docs/README_RU.md ADDED
@@ -0,0 +1,312 @@
1
+ # MapLibre Preview
2
+
3
+ Ruby gem для разработки инструментов MapLibre GL JS стилей с расширенной фильтрацией, визуализацией рельефа и мониторингом производительности. Предназначен для бесшовной интеграции в Sinatra приложения.
4
+
5
+ [![Ruby](https://img.shields.io/badge/ruby-2.7+-red.svg)](https://ruby-lang.org)
6
+ [![Sinatra](https://img.shields.io/badge/sinatra-web_framework-lightgrey.svg)](http://sinatrarb.com/)
7
+ [![MapLibre](https://img.shields.io/badge/maplibre-gl_js-blue.svg)](https://maplibre.org/)
8
+ [![English](https://img.shields.io/badge/english-documentation-green.svg)](../README.md)
9
+
10
+ ## Ключевые возможности
11
+
12
+ - **Расширенная фильтрация слоев**: Фильтрация слоев на основе метаданных с поддержкой сложных выражений фильтров
13
+ - **Визуализация рельефа**: Полная поддержка рельефа с профилями высот и генерацией изолиний
14
+ - **Мониторинг производительности**: Мониторинг FPS, использования памяти и загрузки тайлов в реальном времени
15
+ - **Интерактивная отладка**: Режимы наведения и клика для инспекции объектов
16
+ - **Интеграция с Sinatra**: Бесшовная интеграция как расширение Sinatra с вспомогательными методами
17
+ - **Обслуживание статических ресурсов**: Встроенный middleware для обслуживания JavaScript модулей без конфликтов
18
+
19
+ ## Обзор архитектуры
20
+
21
+ Gem состоит из нескольких интегрированных компонентов:
22
+
23
+ ### Основные компоненты
24
+
25
+ - **[Основной модуль](../lib/maplibre-preview.rb)** - Основная функциональность gem включая расширение Sinatra, Rack middleware, вспомогательные методы и автономное приложение
26
+ - **[Slim шаблоны](../lib/maplibre-preview/views/)** - HTML шаблоны для интерфейса карты
27
+ - **[JavaScript модули](../lib/maplibre-preview/public/js/)** - Клиентская логика фильтрации и рельефа
28
+
29
+ ### Поток данных
30
+
31
+ 1. **Интеграция Sinatra** → Регистрация расширения → Настройка опций → Использование помощников
32
+ 2. **Обслуживание ресурсов** → StaticMiddleware перехватывает запросы `/js/*` → Обслуживает из gem
33
+ 3. **Рендеринг карты** → Вспомогательные методы рендерят Slim шаблоны → Включают внешние зависимости
34
+ 4. **Клиентское взаимодействие** → JavaScript модули обрабатывают фильтрацию и функции рельефа
35
+
36
+ ## Быстрый старт
37
+
38
+ ### Установка
39
+
40
+ Добавьте в ваш Gemfile:
41
+
42
+ ```ruby
43
+ gem 'maplibre-preview'
44
+ ```
45
+
46
+ Затем выполните:
47
+
48
+ ```bash
49
+ bundle install
50
+ ```
51
+
52
+ ### Базовая интеграция
53
+
54
+ ```ruby
55
+ require 'maplibre-preview'
56
+
57
+ class MyApp < Sinatra::Base
58
+ register MapLibrePreview::Extension
59
+
60
+ get '/map' do
61
+ render_maplibre_preview
62
+ end
63
+ end
64
+ ```
65
+
66
+ ### Передача URL стиля
67
+
68
+ Есть несколько способов передать URL стиля карте:
69
+
70
+ **1. Через параметр URL:**
71
+ ```
72
+ http://localhost:9292/map?style_url=https://example.com/style.json
73
+ ```
74
+
75
+ **2. Через параметр маршрута:**
76
+ ```ruby
77
+ get '/map' do
78
+ params[:style_url] = 'https://example.com/style.json'
79
+ render_maplibre_preview
80
+ end
81
+ ```
82
+
83
+ **3. Через параметр source:**
84
+ ```
85
+ http://localhost:9292/map?source=Example_Style
86
+ ```
87
+
88
+ ### Автономный сервер разработки
89
+
90
+ Gem включает полное Sinatra приложение для тестирования и разработки:
91
+
92
+ ```ruby
93
+ require 'maplibre-preview'
94
+
95
+ # Запуск автономного сервера разработки
96
+ MapLibrePreview::App.run!
97
+ ```
98
+
99
+ Это запускает полноценный веб-сервер с:
100
+ - Интерфейсом карты по адресу `http://localhost:4567/map`
101
+ - Обслуживанием JavaScript ресурсов из `/js/*`
102
+ - Всей функциональностью gem из коробки
103
+
104
+ **Как использовать со стилем:**
105
+ - Передать URL стиля как параметр: `http://localhost:4567/map?style_url=https://example.com/style.json`
106
+
107
+ **Без стиля:**
108
+ - Показывает только базовые тайлы (OpenStreetMap)
109
+ - Полезно для тестирования базовой функциональности
110
+ - Без пользовательских слоев и стилизации
111
+
112
+ **Случаи использования:**
113
+ - Быстрое тестирование функциональности gem
114
+ - Разработка и отладка
115
+ - Демонстрация возможностей
116
+
117
+ ## Конфигурация
118
+
119
+ Gem использует фиксированные настройки:
120
+
121
+ - **Центр карты**: `[35.15, 47.41]`
122
+ - **Начальный зум**: `2`
123
+ - **Базовая карта**: Тайлы OpenStreetMap с прозрачностью 0.8
124
+ - **Версии библиотек**: MapLibre GL JS 5.7.3, MapLibre Contour 0.1.0, D3.js 7
125
+
126
+ **URL стиля**: Передается через параметр URL `?style_url=https://example.com/style.json`
127
+
128
+ ## Справочник API
129
+
130
+ ### Расширение Sinatra
131
+
132
+ ```ruby
133
+ # Регистрация расширения
134
+ register MapLibrePreview::Extension
135
+ ```
136
+
137
+ ### Вспомогательные методы
138
+
139
+ | Метод | Описание | Параметры |
140
+ |-------|----------|-----------|
141
+ | `render_maplibre_preview` | Рендеринг полного интерфейса разработки карт | Нет |
142
+ | `render_map_layout` | Рендеринг только макета карты | Нет |
143
+ | `style_url` | Получение текущего URL стиля из параметров | Нет |
144
+ | `should_show_map?` | Проверка, должна ли отображаться карта | Нет |
145
+
146
+ ### Автономное приложение
147
+
148
+ ```ruby
149
+ # Доступные маршруты
150
+ GET /map # Основной интерфейс разработки карт
151
+ GET /js/:file # Обслуживание JavaScript ресурсов
152
+ ```
153
+
154
+ ## Поддержка метаданных стилей
155
+
156
+ Gem поддерживает расширенную фильтрацию через метаданные стилей:
157
+
158
+ ```json
159
+ {
160
+ "metadata": {
161
+ "filters": {
162
+ "buildings": [
163
+ {
164
+ "id": "residential",
165
+ "filter": ["==", ["get", "type"], "residential"]
166
+ },
167
+ {
168
+ "id": "commercial",
169
+ "filter": ["==", ["get", "type"], "commercial"]
170
+ }
171
+ ]
172
+ },
173
+ "locale": {
174
+ "en": {
175
+ "buildings": "Buildings",
176
+ "residential": "Residential",
177
+ "commercial": "Commercial"
178
+ }
179
+ }
180
+ }
181
+ }
182
+ ```
183
+
184
+ ## Поддержка рельефа
185
+
186
+ Для визуализации рельефа добавьте конфигурацию рельефа в ваш стиль:
187
+
188
+ ```json
189
+ {
190
+ "terrain": {
191
+ "source": "terrain-source"
192
+ },
193
+ "sources": {
194
+ "terrain-source": {
195
+ "type": "raster-dem",
196
+ "tiles": ["https://your-terrain-tiles/{z}/{x}/{y}.png"],
197
+ "encoding": "terrarium"
198
+ }
199
+ }
200
+ }
201
+ ```
202
+
203
+ ## Мониторинг производительности
204
+
205
+ Gem включает мониторинг производительности в реальном времени:
206
+
207
+ - **FPS и время кадра**: Производительность рендеринга в реальном времени
208
+ - **Использование памяти**: Мониторинг памяти кучи JavaScript
209
+ - **Загрузка тайлов**: Количество активных тайлов и статус загрузки
210
+ - **Управление слоями**: Количество активных слоев и видимость
211
+ - **Уровень масштабирования**: Текущий уровень масштабирования карты
212
+ - **Статус рельефа**: Доступность данных рельефа
213
+
214
+ ## Структура файлов
215
+
216
+ ```
217
+ lib/
218
+ ├── maplibre-preview.rb # Основной модуль gem и интеграция Sinatra
219
+ └── maplibre-preview/
220
+ ├── version.rb # Версия gem
221
+ ├── views/ # Slim шаблоны
222
+ │ ├── map.slim # Основной интерфейс карты
223
+ │ └── map_layout.slim # HTML макет
224
+ └── public/js/ # JavaScript модули
225
+ ├── filters.js # Логика фильтрации слоев
226
+ └── contour.js # Функции рельефа и изолиний
227
+ ```
228
+
229
+ ## Разработка
230
+
231
+ ### Предварительные требования
232
+
233
+ - Ruby 2.7+
234
+ - Sinatra 2.1+
235
+ - Slim 4.1+
236
+ - Rack 2.0+
237
+
238
+ ### Настройка
239
+
240
+ ```bash
241
+ # Установка зависимостей
242
+ bundle install
243
+
244
+ # Запуск тестов
245
+ bundle exec rspec
246
+
247
+ # Запуск RuboCop
248
+ bundle exec rubocop
249
+
250
+ # Сборка gem
251
+ gem build maplibre-preview.gemspec
252
+ ```
253
+
254
+ ### Тестирование
255
+
256
+ ```bash
257
+ # Запуск всех тестов
258
+ bundle exec rspec
259
+
260
+ # Запуск конкретного файла тестов
261
+ bundle exec rspec spec/maplibre_preview_spec.rb
262
+ ```
263
+
264
+ ## Примеры интеграции
265
+
266
+ ### Базовая интеграция карты
267
+
268
+ ```ruby
269
+ class MyApp < Sinatra::Base
270
+ register MapLibrePreview::Extension
271
+
272
+ get '/map' do
273
+ render_maplibre_preview
274
+ end
275
+ end
276
+ ```
277
+
278
+ ### Интеграция URL стиля
279
+
280
+ ```ruby
281
+ class MyApp < Sinatra::Base
282
+ register MapLibrePreview::Extension
283
+
284
+ get '/map' do
285
+ # URL стиля передается через params[:style_url]
286
+ render_maplibre_preview
287
+ end
288
+ end
289
+ ```
290
+
291
+ ### Множественные маршруты карт
292
+
293
+ ```ruby
294
+ class MyApp < Sinatra::Base
295
+ register MapLibrePreview::Extension
296
+
297
+ get '/map' do
298
+ # Использует params[:style_url] если предоставлен
299
+ render_maplibre_preview
300
+ end
301
+
302
+ get '/terrain' do
303
+ # Устанавливаем URL стиля через params
304
+ params[:style_url] = 'https://example.com/terrain-style.json'
305
+ render_maplibre_preview
306
+ end
307
+ end
308
+ ```
309
+
310
+ ## Лицензия
311
+
312
+ Этот проект лицензирован под лицензией MIT - см. файл [LICENSE](../LICENSE) для деталей.
@@ -0,0 +1,85 @@
1
+ class ContourManager {
2
+ constructor(options) {
3
+ this.map = options.map;
4
+ this.currentStyle = null;
5
+ this.demSource = null;
6
+ }
7
+
8
+ init() {
9
+ if (!this.map || !window.mlcontour) return;
10
+
11
+ try {
12
+ this.currentStyle = this.map.getStyle();
13
+ if (this.currentStyle?.terrain) {
14
+ this.initializeDemSource();
15
+ }
16
+ } catch (e) {
17
+ console.warn('Contour initialization failed:', e);
18
+ }
19
+ }
20
+
21
+ initializeDemSource() {
22
+ if (!this.currentStyle?.terrain || !window.mlcontour) return;
23
+
24
+ try {
25
+ const terrainSourceName = this.currentStyle.terrain.source;
26
+ const terrainSource = this.currentStyle.sources[terrainSourceName];
27
+
28
+ if (!terrainSource || terrainSource.type !== 'raster-dem') return;
29
+
30
+ this.demSource = new mlcontour.DemSource({
31
+ url: terrainSource.tiles[0],
32
+ encoding: terrainSource.encoding || 'terrarium', // "mapbox" or "terrarium"
33
+ maxzoom: terrainSource.maxzoom || 15,
34
+ worker: true, // offload isoline computation to a web worker
35
+ cacheSize: 100, // number of most-recent tiles to cache
36
+ timeoutMs: 10_000 // timeout on fetch requests
37
+ });
38
+
39
+ this.demSource.setupMaplibre(maplibregl);
40
+
41
+ this.updateContourSource(terrainSourceName);
42
+
43
+ console.log('DemSource initialized for contours');
44
+ } catch (e) {
45
+ console.warn('DemSource initialization failed:', e);
46
+ }
47
+ }
48
+
49
+ updateContourSource(terrainSourceName) {
50
+ const contourSourceName = `${terrainSourceName}_contours`;
51
+
52
+ if (this.map.getSource(contourSourceName)) {
53
+ const contourProtocolUrl = this.demSource.contourProtocolUrl({
54
+ multiplier: 1,
55
+ thresholds: {
56
+ // zoom: [minor, major]
57
+ 11: [200, 1000],
58
+ 12: [100, 500],
59
+ 14: [50, 200],
60
+ 15: [20, 100]
61
+ },
62
+ contourLayer: 'contours',
63
+ elevationKey: 'ele',
64
+ levelKey: 'level',
65
+ extent: 4096,
66
+ buffer: 1
67
+ });
68
+
69
+ this.map.getSource(contourSourceName).setTiles([contourProtocolUrl]);
70
+ }
71
+ }
72
+
73
+ updateStyle(newStyle) {
74
+ this.currentStyle = newStyle;
75
+ if (newStyle?.terrain) {
76
+ this.initializeDemSource();
77
+ }
78
+ }
79
+
80
+ cleanup() {
81
+ if (this.demSource) {
82
+ this.demSource = null;
83
+ }
84
+ }
85
+ }