map_view 0.0.1a → 0.1.0.pre.alpha
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/README.md +0 -188
- data/Rakefile +7 -0
- data/app/controllers/map_view/maps_controller.rb +20 -0
- data/config/initializers/map_view.rb +4 -0
- data/config/routes.rb +4 -0
- data/lib/generators/map_view/install_generator.rb +65 -0
- data/lib/generators/map_view/templates/default_styles.yml +45 -0
- data/lib/generators/map_view/templates/initializer.rb +14 -0
- data/lib/generators/map_view/templates/maps_controller.rb +15 -0
- data/lib/map_view/config.rb +67 -0
- data/lib/map_view/engine.rb +39 -0
- data/lib/map_view/version.rb +4 -0
- data/lib/map_view/view_helper.rb +116 -0
- data/lib/map_view.rb +24 -0
- metadata +83 -39
- data/lib/gd/gis/basemap.rb +0 -178
- data/lib/gd/gis/classifier.rb +0 -57
- data/lib/gd/gis/color_helpers.rb +0 -65
- data/lib/gd/gis/crs_normalizer.rb +0 -57
- data/lib/gd/gis/feature.rb +0 -153
- data/lib/gd/gis/geometry.rb +0 -235
- data/lib/gd/gis/input/detector.rb +0 -34
- data/lib/gd/gis/layer_geojson.rb +0 -66
- data/lib/gd/gis/layer_lines.rb +0 -44
- data/lib/gd/gis/layer_points.rb +0 -78
- data/lib/gd/gis/layer_polygons.rb +0 -54
- data/lib/gd/gis/map.rb +0 -370
- data/lib/gd/gis/middleware.rb +0 -89
- data/lib/gd/gis/ontology.rb +0 -26
- data/lib/gd/gis/ontology.yml +0 -28
- data/lib/gd/gis/projection.rb +0 -39
- data/lib/gd/gis/style.rb +0 -45
- data/lib/gd/gis.rb +0 -15
- data/lib/libgd_gis.rb +0 -44
- /data/{lib/gd/gis/input/geojson.rb → MIT-LICENSE} +0 -0
- /data/{lib/gd/gis/input/kml.rb → app/assets/stylesheets/map_view.css} +0 -0
- /data/{lib/gd/gis/input/shapefile.rb → app/views/map_view/_map.html.erb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 71caf1dd97b22c96824dcf9bdd59cfab0a7665d2640f615618964b5dd95d2068
|
|
4
|
+
data.tar.gz: 6d8cbc42a9b9d0c0057af57e1d6f375310f568b30e78c0be84c3742930a9950d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c6d29c2d7670bb8e0d66b189887fe4c0243d48bc17a9b7ef4f3be62fed8afc3844be892a9bfc856199f96ecfa0e0d42de1c5372cd09f8b8abac3ed3069ea00a3
|
|
7
|
+
data.tar.gz: 9122c3ba6cb9039fe147a2f157dd2e38eb5e023049efd9ae89108d07288d1f493a9394eec2395075967ccb64614e97ff43b4f9793c9376e3fbdfa23b554b7185
|
data/README.md
CHANGED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
# LibGD-GIS
|
|
2
|
-
|
|
3
|
-
<p align="center">
|
|
4
|
-
<a href="https://rubystacknews.com/2026/01/07/ruby-can-now-draw-maps-and-i-started-with-ice-cream/">
|
|
5
|
-
<img src="https://img.shields.io/badge/RubyStackNews-CC342D?style=for-the-badge&logo=ruby&logoColor=white" />
|
|
6
|
-
</a>
|
|
7
|
-
<a href="https://x.com/ruby_stack_news">
|
|
8
|
-
<img src="https://img.shields.io/badge/Twitter%20@RubyStackNews-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white" />
|
|
9
|
-
</a>
|
|
10
|
-
<a href="https://www.linkedin.com/in/germ%C3%A1n-silva-56a12622/">
|
|
11
|
-
<img src="https://img.shields.io/badge/Germán%20Silva-0A66C2?style=for-the-badge&logo=linkedin&logoColor=white" />
|
|
12
|
-
</a>
|
|
13
|
-
</p>
|
|
14
|
-
|
|
15
|
-
<p align="center">
|
|
16
|
-
<a href="https://rubygems.org/gems/libgd-gis">
|
|
17
|
-
<img src="https://img.shields.io/badge/RubyGems-libgd--gis-CC342D?style=for-the-badge&logo=rubygems&logoColor=white" />
|
|
18
|
-
</a>
|
|
19
|
-
<a href="https://github.com/ggerman/libgd-gis">
|
|
20
|
-
<img src="https://img.shields.io/badge/GitHub-libgd--gis-181717?style=for-the-badge&logo=github&logoColor=white" />
|
|
21
|
-
</a>
|
|
22
|
-
<a href="https://github.com/ggerman/ruby-libgd">
|
|
23
|
-
<img src="https://img.shields.io/badge/Engine-ruby--libgd-CC342D?style=for-the-badge&logo=ruby&logoColor=white" />
|
|
24
|
-
</a>
|
|
25
|
-
</p>
|
|
26
|
-
|
|
27
|
-
<p align="right">
|
|
28
|
-
<img src="docs/images/logo-gis.png" width="160" />
|
|
29
|
-
</p>
|
|
30
|
-
|
|
31
|
-

|
|
32
|
-
[](https://www.codacy.com/app/libgd-gis/libgd-gis?utm_source=github.com&utm_medium=referral&utm_content=libgd-gis/libgd-gis&utm_campaign=Badge_Grade)
|
|
33
|
-
[](https://coveralls.io/github/libgd-gis/libgd-gis?branch=master)
|
|
34
|
-
[](https://rubygems.org/gems/libgd-gis)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
| Examples | Examples | Examples |
|
|
38
|
-
| :----: | :----: | :--: |
|
|
39
|
-
| <img src="docs/examples/parana.png" height="250"> | <img src="docs/examples/nyc.png" height="250"> | <img src="docs/examples/paris.png" height="250"> |
|
|
40
|
-
| <img src="examples/nyc/nyc.png" height="250"> | <img src="docs/examples/tokyo_solarized.png" height="250"> | <img src="examples/parana/parana.png" height="250"> |
|
|
41
|
-
| <img src="docs/examples/america.png" height="250"> | <img src="docs/examples/argentina_museum.png" height="250"> | <img src="docs/examples/museos_parana.png" height="250"> |
|
|
42
|
-
| <img src="docs/examples/asia.png" height="250"> | <img src="docs/examples/europe.png" height="250"> | <img src="docs/examples/icecream_parana.png" height="250"> |
|
|
43
|
-
| <img src="docs/examples/argentina_cities.png" height="250"> | <img src="docs/examples/tanzania_hydro.png" height="250"> | <img src="docs/examples/parana_polygon.png" height="250"> |
|
|
44
|
-
| <img src="docs/examples/parana_carto_dark.png" height="250"> | <img src="docs/examples/ramirez_avenue.png" height="250"> | <img src="examples/paris/paris.png" height="250"> |
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
> **libgd-gis is evolving very fast**, so some examples may temporarily stop working.
|
|
49
|
-
> Please report issues or ask for help — feedback is very welcome.
|
|
50
|
-
> https://github.com/ggerman/libgd-gis/issues or ggerman@gmail.com
|
|
51
|
-
|
|
52
|
-
--
|
|
53
|
-
|
|
54
|
-
## A geospatial raster engine for Ruby.
|
|
55
|
-
|
|
56
|
-
libgd-gis allows Ruby to render real maps, GeoJSON layers, vector features, and geospatial tiles using a native raster backend powered by **libgd**.
|
|
57
|
-
|
|
58
|
-
It restores something Ruby lost over time:
|
|
59
|
-
the ability to generate **maps, tiles, and GIS-grade visualizations natively**, without relying on external tools like QGIS, Mapnik, ImageMagick, or Mapbox.
|
|
60
|
-
|
|
61
|
-
Built on top of **ruby-libgd**, this project turns Ruby into a **map rendering engine**, capable of producing spatial graphics, tiled maps, and geospatial outputs directly inside Ruby processes.
|
|
62
|
-
|
|
63
|
-
- No external renderers.
|
|
64
|
-
- No shelling out.
|
|
65
|
-
- Just Ruby, raster, and GIS.
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
## What is this?
|
|
70
|
-
|
|
71
|
-
`libgd-gis` is a **geospatial rendering engine** for Ruby built on top of [`ruby-libgd`](https://github.com/ggerman/ruby-libgd).
|
|
72
|
-
|
|
73
|
-
It allows you to:
|
|
74
|
-
|
|
75
|
-
- Load GeoJSON, CSV, or any dataset with coordinates
|
|
76
|
-
- Fetch real basemap tiles
|
|
77
|
-
- Reproject WGS84 (lat/lon) into Web Mercator
|
|
78
|
-
- Render points, icons, and layers onto a raster map
|
|
79
|
-
- Generate PNG maps or map tiles
|
|
80
|
-
|
|
81
|
-
This is the same type of pipeline used by professional GIS systems — implemented in Ruby.
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## Installation
|
|
86
|
-
|
|
87
|
-
### System dependency
|
|
88
|
-
|
|
89
|
-
`libgd-gis` depends on **libgd**, via `ruby-libgd`.
|
|
90
|
-
|
|
91
|
-
Install libgd first:
|
|
92
|
-
|
|
93
|
-
**Ubuntu / Debian**
|
|
94
|
-
```
|
|
95
|
-
sudo apt install libgd-dev
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
**macOS**
|
|
99
|
-
```
|
|
100
|
-
brew install gd
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
### Ruby gems
|
|
106
|
-
|
|
107
|
-
```
|
|
108
|
-
gem install ruby-libgd
|
|
109
|
-
gem install libgd-gis
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## Quick Example
|
|
115
|
-
|
|
116
|
-
Render hydroelectric plants from a GeoJSON file:
|
|
117
|
-
|
|
118
|
-
```ruby
|
|
119
|
-
require "json"
|
|
120
|
-
require "gd/gis"
|
|
121
|
-
|
|
122
|
-
# ---------------------------
|
|
123
|
-
# Bounding box mundial
|
|
124
|
-
# ---------------------------
|
|
125
|
-
AMERICA = [-170, -60, -30, 75]
|
|
126
|
-
|
|
127
|
-
# ---------------------------
|
|
128
|
-
# Crear mapa
|
|
129
|
-
# ---------------------------
|
|
130
|
-
map = GD::GIS::Map.new(
|
|
131
|
-
bbox: AMERICA,
|
|
132
|
-
zoom: 4,
|
|
133
|
-
basemap: :carto_light
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
# Cargar datos
|
|
137
|
-
# ---------------------------
|
|
138
|
-
peaks = JSON.parse(File.read("picks.json"))
|
|
139
|
-
|
|
140
|
-
# ---------------------------
|
|
141
|
-
# Agregar capa de puntos
|
|
142
|
-
# ---------------------------
|
|
143
|
-
map.add_points(
|
|
144
|
-
peaks,
|
|
145
|
-
lon: ->(p) { p["longitude"] },
|
|
146
|
-
lat: ->(p) { p["latitude"] },
|
|
147
|
-
icon: "peak.png",
|
|
148
|
-
label: ->(p) { p["name"] },
|
|
149
|
-
font: "./fonts/DejaVuSans.ttf",
|
|
150
|
-
size: 10,
|
|
151
|
-
color: [0,0,0]
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
# ---------------------------
|
|
155
|
-
# Renderizar y guardar
|
|
156
|
-
# ---------------------------
|
|
157
|
-
map.render
|
|
158
|
-
map.save("output/america.png")
|
|
159
|
-
|
|
160
|
-
puts "Saved output/america.png"
|
|
161
|
-
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
---
|
|
165
|
-
|
|
166
|
-
## Features
|
|
167
|
-
|
|
168
|
-
- Real basemap tiles
|
|
169
|
-
- WGS84 → Web Mercator projection
|
|
170
|
-
- GeoJSON point rendering
|
|
171
|
-
- CSV / JSON support
|
|
172
|
-
- Icon-based symbol layers
|
|
173
|
-
- Automatic bounding box fitting
|
|
174
|
-
- Raster output (PNG)
|
|
175
|
-
|
|
176
|
-
---
|
|
177
|
-
|
|
178
|
-
## License
|
|
179
|
-
|
|
180
|
-
MIT
|
|
181
|
-
|
|
182
|
-
---
|
|
183
|
-
|
|
184
|
-
## Author
|
|
185
|
-
|
|
186
|
-
Germán Silva
|
|
187
|
-
https://github.com/ggerman
|
|
188
|
-
https://rubystacknews.com
|
data/Rakefile
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# app/controllers/map_view/maps_controller.rb
|
|
2
|
+
module MapView
|
|
3
|
+
class MapsController < ApplicationController
|
|
4
|
+
def show
|
|
5
|
+
file_path = Rails.root.join("public", "map_cache", params[:path])
|
|
6
|
+
|
|
7
|
+
Rails.logger.info "=== MAP_VIEW DEBUG ==="
|
|
8
|
+
Rails.logger.info "Params: #{params.inspect}"
|
|
9
|
+
Rails.logger.info "Looking for: #{file_path}"
|
|
10
|
+
Rails.logger.info "File exists? #{File.exist?(file_path)}"
|
|
11
|
+
|
|
12
|
+
if File.exist?(file_path)
|
|
13
|
+
send_file file_path, type: "image/png", disposition: "inline"
|
|
14
|
+
else
|
|
15
|
+
Rails.logger.info "File NOT FOUND!"
|
|
16
|
+
head :not_found
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# lib/generators/map_view/install_generator.rb
|
|
2
|
+
require "rails/generators/base"
|
|
3
|
+
|
|
4
|
+
module MapView
|
|
5
|
+
module Generators
|
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
|
7
|
+
source_root File.expand_path("templates", __dir__)
|
|
8
|
+
|
|
9
|
+
desc "Installs MapView configuration files"
|
|
10
|
+
|
|
11
|
+
def copy_initializer
|
|
12
|
+
template "initializer.rb", "config/initializers/map_view.rb"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create_styles_directory
|
|
16
|
+
empty_directory "config/map_view/styles"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def copy_default_style
|
|
20
|
+
template "default_styles.yml", "config/map_view/styles/default.yml"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def create_cache_directory
|
|
24
|
+
empty_directory "public/map_cache"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def add_route
|
|
28
|
+
route <<~RUBY
|
|
29
|
+
# Serve cached map images
|
|
30
|
+
get "/map_cache/*path" => "map_view/maps#show", :as => :map_cache
|
|
31
|
+
RUBY
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def add_routes
|
|
35
|
+
route <<~RUBY
|
|
36
|
+
# MapView routes for serving cached map images
|
|
37
|
+
get "/map_cache/*path" => "map_view/maps#show", :as => :map_cache
|
|
38
|
+
RUBY
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def create_controller
|
|
42
|
+
template "maps_controller.rb", "app/controllers/map_view/maps_controller.rb"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def display_post_install_message
|
|
46
|
+
puts <<~MSG
|
|
47
|
+
|
|
48
|
+
═══════════════════════════════════════════════════════════════════════════
|
|
49
|
+
MapView installed successfully!
|
|
50
|
+
|
|
51
|
+
Next steps:
|
|
52
|
+
1. Ensure libgd-gis is installed and working
|
|
53
|
+
2. Restart your Rails server
|
|
54
|
+
3. Use in your views:
|
|
55
|
+
<%= map_view("path/to/data.geojson", bbox: :argentina) %>
|
|
56
|
+
|
|
57
|
+
Configuration file: config/initializers/map_view.rb
|
|
58
|
+
Styles directory: config/map_view/styles/
|
|
59
|
+
═══════════════════════════════════════════════════════════════════════════
|
|
60
|
+
|
|
61
|
+
MSG
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# config/map_view/styles/default.yml
|
|
2
|
+
# Default map style for MapView
|
|
3
|
+
|
|
4
|
+
global:
|
|
5
|
+
background: [15, 23, 42]
|
|
6
|
+
|
|
7
|
+
roads:
|
|
8
|
+
motorway:
|
|
9
|
+
stroke: [239, 68, 68]
|
|
10
|
+
stroke_width: 3
|
|
11
|
+
primary:
|
|
12
|
+
stroke: [245, 158, 11]
|
|
13
|
+
stroke_width: 2.5
|
|
14
|
+
secondary:
|
|
15
|
+
stroke: [251, 191, 36]
|
|
16
|
+
stroke_width: 2
|
|
17
|
+
street:
|
|
18
|
+
stroke: [229, 231, 235]
|
|
19
|
+
stroke_width: 1.5
|
|
20
|
+
minor:
|
|
21
|
+
stroke: [156, 163, 175]
|
|
22
|
+
stroke_width: 1
|
|
23
|
+
|
|
24
|
+
rails:
|
|
25
|
+
stroke: [156, 163, 175]
|
|
26
|
+
stroke_width: 2
|
|
27
|
+
|
|
28
|
+
water:
|
|
29
|
+
stroke: [59, 130, 246]
|
|
30
|
+
stroke_width: 1.5
|
|
31
|
+
|
|
32
|
+
parks:
|
|
33
|
+
fill: [34, 197, 94]
|
|
34
|
+
fill_opacity: 0.5
|
|
35
|
+
|
|
36
|
+
points:
|
|
37
|
+
color: [239, 68, 68]
|
|
38
|
+
radius: 4
|
|
39
|
+
|
|
40
|
+
order:
|
|
41
|
+
- water
|
|
42
|
+
- parks
|
|
43
|
+
- rails
|
|
44
|
+
- roads
|
|
45
|
+
- points
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# config/initializers/map_view.rb
|
|
2
|
+
MapView.configure do |config|
|
|
3
|
+
# Map defaults
|
|
4
|
+
config.default_zoom = 10
|
|
5
|
+
config.default_basemap = :carto_light
|
|
6
|
+
config.default_width = 800
|
|
7
|
+
config.default_height = 600
|
|
8
|
+
config.default_style = "default"
|
|
9
|
+
config.default_bbox_name = :argentina
|
|
10
|
+
|
|
11
|
+
# Cache settings
|
|
12
|
+
config.cache_enabled = true
|
|
13
|
+
config.cache_dir = "public/map_cache"
|
|
14
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# app/controllers/map_view/maps_controller.rb
|
|
2
|
+
module MapView
|
|
3
|
+
class MapsController < ActionController::Base
|
|
4
|
+
# Serve cached map images
|
|
5
|
+
def show
|
|
6
|
+
cache_path = Rails.root.join("public", "map_cache", params[:path])
|
|
7
|
+
|
|
8
|
+
if File.exist?(cache_path)
|
|
9
|
+
send_file cache_path, type: "image/png", disposition: "inline"
|
|
10
|
+
else
|
|
11
|
+
head :not_found
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# lib/map_view/config.rb
|
|
2
|
+
module MapView
|
|
3
|
+
class Configuration
|
|
4
|
+
# Map defaults
|
|
5
|
+
attr_accessor :default_zoom,
|
|
6
|
+
:default_basemap,
|
|
7
|
+
:default_width,
|
|
8
|
+
:default_height,
|
|
9
|
+
:default_style,
|
|
10
|
+
:default_bbox_name
|
|
11
|
+
|
|
12
|
+
# Cache settings
|
|
13
|
+
attr_accessor :cache_enabled,
|
|
14
|
+
:cache_dir,
|
|
15
|
+
:cache_duration,
|
|
16
|
+
:enable_caching,
|
|
17
|
+
:png_compression
|
|
18
|
+
|
|
19
|
+
def initialize
|
|
20
|
+
# Map defaults
|
|
21
|
+
@default_zoom = 10
|
|
22
|
+
@default_basemap = :carto_light
|
|
23
|
+
@default_width = 800
|
|
24
|
+
@default_height = 600
|
|
25
|
+
@default_style = "default"
|
|
26
|
+
@default_bbox_name = :argentina
|
|
27
|
+
|
|
28
|
+
# Cache settings
|
|
29
|
+
@cache_enabled = true
|
|
30
|
+
@enable_caching = true
|
|
31
|
+
@cache_dir = "public/map_cache"
|
|
32
|
+
@cache_duration = 3600
|
|
33
|
+
@png_compression = 6
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Alias methods for compatibility
|
|
37
|
+
def enable_caching
|
|
38
|
+
@cache_enabled
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def enable_caching=(value)
|
|
42
|
+
@cache_enabled = value
|
|
43
|
+
@enable_caching = value
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def cache_duration=(value)
|
|
47
|
+
@cache_duration = value.respond_to?(:to_i) ? value.to_i : value
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def cache_duration
|
|
51
|
+
@cache_duration
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class << self
|
|
56
|
+
attr_accessor :configuration
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.configure
|
|
60
|
+
self.configuration ||= Configuration.new
|
|
61
|
+
yield(configuration) if block_given?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.configuration
|
|
65
|
+
@configuration ||= Configuration.new
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# lib/map_view/engine.rb
|
|
2
|
+
module MapView
|
|
3
|
+
class Engine < ::Rails::Engine
|
|
4
|
+
isolate_namespace MapView
|
|
5
|
+
|
|
6
|
+
initializer "map_view.static_files" do |app|
|
|
7
|
+
# Servir archivos de map_cache automáticamente
|
|
8
|
+
cache_dir = Rails.root.join(MapView.configuration.cache_dir)
|
|
9
|
+
|
|
10
|
+
app.config.middleware.insert_after(
|
|
11
|
+
Rack::Runtime,
|
|
12
|
+
Rack::Static,
|
|
13
|
+
urls: ["/map_cache"],
|
|
14
|
+
root: cache_dir.to_s
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
initializer "map_view.helpers" do
|
|
19
|
+
ActiveSupport.on_load(:action_view) do
|
|
20
|
+
include MapView::ViewHelper
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
initializer "map_view.routes" do
|
|
25
|
+
# Routes are already added by the generator
|
|
26
|
+
# This ensures the engine routes are loaded
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# lib/map_view/engine.rb
|
|
33
|
+
module MapView
|
|
34
|
+
class Engine < ::Rails::Engine
|
|
35
|
+
isolate_namespace MapView
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# lib/map_view/view_helper.rb
|
|
2
|
+
module MapView
|
|
3
|
+
module ViewHelper
|
|
4
|
+
# Render a map from GeoJSON file
|
|
5
|
+
#
|
|
6
|
+
# @param geojson_path [String] path to GeoJSON file (absolute or relative to Rails.root)
|
|
7
|
+
# @param options [Hash] map options
|
|
8
|
+
# @option options [Symbol, Array] :bbox bounding box (:argentina, :world, or [min_lng, min_lat, max_lng, max_lat])
|
|
9
|
+
# @option options [Integer] :zoom zoom level (default: 10)
|
|
10
|
+
# @option options [Symbol] :basemap basemap provider (default: :carto_light)
|
|
11
|
+
# @option options [Integer] :width image width in pixels (default: 800)
|
|
12
|
+
# @option options [Integer] :height image height in pixels (default: 600)
|
|
13
|
+
# @option options [String] :style style name (default: "default")
|
|
14
|
+
# @option options [String] :alt alt text for img tag
|
|
15
|
+
# @option options [Boolean] :force_render force re-render ignoring cache
|
|
16
|
+
#
|
|
17
|
+
# @return [String] HTML img tag
|
|
18
|
+
#
|
|
19
|
+
# @example Basic usage
|
|
20
|
+
# <%= map_view("data/cities.geojson") %>
|
|
21
|
+
#
|
|
22
|
+
# @example With options
|
|
23
|
+
# <%= map_view("data/cities.geojson", bbox: :argentina, zoom: 6, width: 600, height: 400) %>
|
|
24
|
+
#
|
|
25
|
+
# @example With style
|
|
26
|
+
# <%= map_view("data/cities.geojson", style: "dark") %>
|
|
27
|
+
def map_view(geojson_path, options = {})
|
|
28
|
+
# Normalize path
|
|
29
|
+
full_path = geojson_path.start_with?("/") ? geojson_path : Rails.root.join(geojson_path).to_s
|
|
30
|
+
|
|
31
|
+
# Generate cache key
|
|
32
|
+
cache_key = generate_cache_key(full_path, options)
|
|
33
|
+
cache_path = Rails.root.join(MapView.configuration.cache_dir, "#{cache_key}.png")
|
|
34
|
+
|
|
35
|
+
# Return cached image if exists and not forcing re-render
|
|
36
|
+
if File.exist?(cache_path) && !options[:force_render]
|
|
37
|
+
return tag.img(src: "/map_cache/#{cache_key}.png", alt: options[:alt] || "Map", class: "map-view")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Build map using libgd-gis
|
|
41
|
+
bbox = MapView.resolve_bbox(options[:bbox] || MapView.configuration.default_bbox_name)
|
|
42
|
+
zoom = 4 # options[:zoom] || MapView.configuration.default_zoom
|
|
43
|
+
basemap = options[:basemap] || MapView.configuration.default_basemap
|
|
44
|
+
pp zoom
|
|
45
|
+
map = GD::GIS::Map.new(bbox: bbox, zoom: zoom, basemap: basemap)
|
|
46
|
+
|
|
47
|
+
# Add GeoJSON data
|
|
48
|
+
map.add_geojson(full_path)
|
|
49
|
+
|
|
50
|
+
# Apply style
|
|
51
|
+
style_name = options[:style] || MapView.configuration.default_style
|
|
52
|
+
map.style = load_style(style_name)
|
|
53
|
+
|
|
54
|
+
# Render and save
|
|
55
|
+
map.render
|
|
56
|
+
FileUtils.mkdir_p(File.dirname(cache_path))
|
|
57
|
+
map.save(cache_path.to_s)
|
|
58
|
+
|
|
59
|
+
# Return img tag
|
|
60
|
+
tag.img(src: "/map_cache/#{cache_key}.png", alt: options[:alt] || "Map", class: "map-view")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Render a map with a single point
|
|
64
|
+
#
|
|
65
|
+
# @param lon [Float] longitude
|
|
66
|
+
# @param lat [Float] latitude
|
|
67
|
+
# @param options [Hash] map options (same as map_view)
|
|
68
|
+
# @option options [String] :label point label
|
|
69
|
+
#
|
|
70
|
+
# @example
|
|
71
|
+
# <%= map_view_point(-58.3816, -34.6037, label: "Buenos Aires", zoom: 12) %>
|
|
72
|
+
def map_view_point(lon, lat, options = {})
|
|
73
|
+
# Create temporary GeoJSON
|
|
74
|
+
geojson = {
|
|
75
|
+
type: "FeatureCollection",
|
|
76
|
+
features: [{
|
|
77
|
+
type: "Feature",
|
|
78
|
+
geometry: {
|
|
79
|
+
type: "Point",
|
|
80
|
+
coordinates: [lon, lat]
|
|
81
|
+
},
|
|
82
|
+
properties: {
|
|
83
|
+
name: options[:label]
|
|
84
|
+
}
|
|
85
|
+
}]
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
temp_file = write_temp_geojson(geojson)
|
|
89
|
+
map_view(temp_file.path, options.except(:label))
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def generate_cache_key(path, options)
|
|
95
|
+
key = { path: path, options: options.except(:force_render, :alt, :class) }
|
|
96
|
+
Digest::MD5.hexdigest(key.to_s)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def load_style(style_name)
|
|
100
|
+
style_path = Rails.root.join("config", "map_view", "styles", "#{style_name}.yml")
|
|
101
|
+
|
|
102
|
+
if File.exist?(style_path)
|
|
103
|
+
GD::GIS::Style.load(style_name, from: Rails.root.join("config", "map_view", "styles"))
|
|
104
|
+
else
|
|
105
|
+
GD::GIS::Style.default
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def write_temp_geojson(geojson)
|
|
110
|
+
temp = Tempfile.new(["map_view", ".geojson"])
|
|
111
|
+
temp.write(JSON.generate(geojson))
|
|
112
|
+
temp.rewind
|
|
113
|
+
temp
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
data/lib/map_view.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# lib/map_view.rb
|
|
2
|
+
require "map_view/version"
|
|
3
|
+
require "map_view/engine"
|
|
4
|
+
require "map_view/config"
|
|
5
|
+
require "map_view/view_helper"
|
|
6
|
+
|
|
7
|
+
module MapView
|
|
8
|
+
class << self
|
|
9
|
+
# Delegate bbox resolution to libgd-gis
|
|
10
|
+
def resolve_bbox(bbox_or_name)
|
|
11
|
+
GD::GIS::BBoxResolver.resolve(bbox_or_name)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Access to all available extent names from libgd-gis
|
|
15
|
+
def available_extents
|
|
16
|
+
GD::GIS::Extents.all
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Root directory of the gem
|
|
20
|
+
def root
|
|
21
|
+
File.expand_path("..", __dir__)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|