maplibre-preview 0.0.2 → 1.1.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.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +16 -0
- data/.rspec +3 -0
- data/.rubocop.yml +260 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +51 -0
- data/LICENSE +21 -0
- data/README.md +312 -0
- data/Rakefile +50 -0
- data/docs/README_RU.md +312 -0
- data/lib/maplibre-preview/public/js/contour.js +85 -0
- data/lib/maplibre-preview/public/js/filters.js +323 -0
- data/lib/maplibre-preview/version.rb +1 -1
- data/lib/maplibre-preview/views/maplibre_layout.slim +329 -0
- data/lib/maplibre-preview/views/maplibre_map.slim +829 -0
- data/lib/maplibre-preview.rb +77 -2
- data/spec/maplibre_preview_spec.rb +52 -0
- data/spec/spec_helper.rb +11 -0
- metadata +88 -35
- data/lib/maplibre-preview/sinatra_ext.rb +0 -27
- data/lib/maplibre-preview/views/maplibre_preview.slim +0 -3
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
|
+
[](https://ruby-lang.org)
|
6
|
+
[](http://sinatrarb.com/)
|
7
|
+
[](https://maplibre.org/)
|
8
|
+
[](../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
|
+
slim :maplibre_map, layout: :maplibre_layout
|
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
|
+
slim :maplibre_map, layout: :maplibre_layout
|
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
|
+
Gem предоставляет Slim шаблоны, которые можно использовать напрямую в маршрутах:
|
140
|
+
|
141
|
+
| Шаблон | Описание | Использование |
|
142
|
+
|--------|----------|---------------|
|
143
|
+
| `maplibre_map` | Основной шаблон интерфейса карты | `slim :maplibre_map, layout: :maplibre_layout` |
|
144
|
+
| `maplibre_layout` | HTML макет с внешними зависимостями | Используется как макет для шаблона карты |
|
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
|
+
slim :maplibre_map, layout: :maplibre_layout
|
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
|
+
slim :maplibre_map, layout: :maplibre_layout
|
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
|
+
slim :maplibre_map, layout: :maplibre_layout
|
300
|
+
end
|
301
|
+
|
302
|
+
get '/terrain' do
|
303
|
+
# Устанавливаем URL стиля через params
|
304
|
+
params[:style_url] = 'https://example.com/terrain-style.json'
|
305
|
+
slim :maplibre_map, layout: :maplibre_layout
|
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
|
+
}
|