Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
mapstatic (0.0.2)
mapstatic (0.1)
mini_magick (~> 4.9)
typhoeus (~> 1.3)

Expand All @@ -18,7 +18,7 @@ GEM
ffi (>= 1.3.0)
ffi (1.11.1)
hashdiff (0.4.0)
mini_magick (4.9.3)
mini_magick (4.9.5)
public_suffix (3.1.1)
rake (12.3.2)
rspec (3.8.0)
Expand Down Expand Up @@ -50,7 +50,7 @@ PLATFORMS
DEPENDENCIES
awesome_print (< 2.0)
mapstatic!
rake (~> 12)
rake
rspec (~> 3)
thor (>= 0.19.0, < 2.0)
vcr (~> 3)
Expand Down
74 changes: 54 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ A CLI and Ruby Gem for generating static maps from map tile servers.
## Installation

gem install mapstatic

if you want to use command line for creating maps then additional gems are required

gem install mapstatic
Expand All @@ -22,31 +22,42 @@ if you want to use command line for creating maps then additional gems are requi
There are two ways to generate a static map from the mapstatic CLI.

1. Specifying a bounding box and zoom level

The command below generates a map of the UK using the [OpenStreetMap](http://www.openstreetmap.org/) tileset. The width and height of the resulting image (`uk.png`) are determined by the bounding box and the zoom level. If you don't know the bounding box of the area then [this is a useful tool](http://boundingbox.klokantech.com/).

```.bash
mapstatic map uk.png \
--zoom=5 \
-- bbox=-11.29,49.78,2.45,58.78
```

![UK](http://matchingnotes.com/images/uk.png)

2. Specifying a center lat, center lng, width, height and zoom level

The command below generates a map of the UK using the [OpenStreetMap](http://www.openstreetmap.org/) tileset. The width and height of the resulting image (`uk.png`) are determined by the bounding box and the zoom level. If you don't know the bounding box of the area then [this is a useful tool](http://boundingbox.klokantech.com/).
Alternatively, you can specify a central latitude and longitude and specify the width and height.

```.bash
mapstatic map uk.png \
--zoom=5 \
--bbox=-11.29,49.78,2.45,58.78
```
```.bash
mapstatic map silicon-roundabout.png \
--zoom=18 \
--lat=51.52567 \
--lng=-0.08750 \
--width=600 \
--height=300
```

![UK](http://matchingnotes.com/images/uk.png)
![Silicon Roundabout](http://matchingnotes.com/images/silicon-roundabout.png)

Alternatively, you can specify a central latitude and longitude and specify the width and height.
Optionally a gpx file can be specified. In that case, the routes and tracks contained in that file will be drawn on top of the map. The map view will be automatically adjusted to fit the given gpx route data.

```.bash
mapstatic map silicon-roundabout.png \
--zoom=18 \
--lat=51.52567 \
--lng=-0.08750 \
mapstatic map map.png \
--zoom=12 \
--width=600 \
--height=300
--height=300 \
--gpx=file.gpx
```

![Silicon Roundabout](http://matchingnotes.com/images/silicon-roundabout.png)

## Changing the provider

Mapstatic can generate maps from any slippy map tile server. The tile provider can be specified with a URL template
Expand Down Expand Up @@ -88,15 +99,38 @@ Mapstatic can be used in your application code to generate maps and get metadata

```.ruby
require 'mapstatic'

# Initialize
map = Mapstatic::Map.new(
:zoom => 12,
:bbox => "-0.218894,51.450943,0.014382,51.553755",
:provider => 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
width: 400,
height: 200
zoom: 11,
provider: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
)
map.render_map 'london.png'

# optional: set geojson data layer
geojson_data = {
type: "FeatureCollection",
features: ... # Currently only LineString is supported by Mapstatic
}
map.geojson = geojson_data
map.fit_bounds # Call this to set map dimensions so that geojson data fits into map area

# Render to file
map.to_file 'london.png'
map.metadata # Returns the map metadata

# You can also just render the image without writing it to a file.
# This will produce a MiniMagic image object.
image = map.to_image
```

### Supported GeoJSON feature types

* LineString

To add support for more types, inherit a new class from Mapstatic::Painter, implement required methods, and add the class to painter_class_for method in `renderer.rb`.

## License

Mapstatic is licensed under the MIT license.
Expand Down
31 changes: 8 additions & 23 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,48 +10,33 @@ RSpec::Core::RakeTask.new do |t|
t.rspec_opts = %w(--format documentation --colour)
end


task :default => ["spec"]

# This builds the actual gem. For details of what all these options
# mean, and other ones you can add, check the documentation here:
#
# http://rubygems.org/read/chapter/20
#
spec = Gem::Specification.new do |s|

# Change these as appropriate
s.name = "mapstatic"
s.version = Mapstatic::VERSION
s.summary = "Static Map Generator"
s.author = "James Croft"
s.authors = ["James Croft", "Mika Haulo", "Tim Neems", "Olli Huotari", "Michael O'Toole"]
s.email = "james@matchingnotes.com"
s.homepage = "https://github.com/crofty/mapstatic"
s.license = "MIT"

s.has_rdoc = true
# You should probably have a README of some kind. Change the filename
# as appropriate
# s.extra_rdoc_files = %w(README)
# s.rdoc_options = %w(--main README)

# Add any extra files to include in the gem (like your README)
s.files = %w(Gemfile Gemfile.lock) + Dir.glob("{spec,lib}/**/*")
s.require_paths = ["lib"]
s.executables << 'mapstatic'

# If you want to depend on other gems, add them here, along with any
# relevant versions
# s.add_dependency("some_other_gem", "~> 0.1.0")
s.add_dependency('mini_magick', '~> 4.9')
s.add_dependency('typhoeus', '~> 1.3')
s.add_dependency('nokogiri', '~> 1.10')

s.add_development_dependency('thor', ['>= 0.19.0', '< 2.0']) # install these if you want to use command line env
s.add_development_dependency('awesome_print', '< 2.0') # install these if you want to use command line env

s.add_development_dependency('rake') # needed so that 'bundle exec rake' will work as expected
s.add_development_dependency('rake', '~> 12') # needed so that 'bundle exec rake' will work as expected
s.add_development_dependency('rspec', '~> 3')
s.add_development_dependency('vcr', '~> 3')
s.add_development_dependency('webmock', '~> 2')

# install these if you want to use command line env
s.add_development_dependency('thor', ['>= 0.19.0', '< 2.0'])
s.add_development_dependency('awesome_print', '< 2.0')
end

# This task actually builds the gem. We also regenerate a static
Expand Down
5 changes: 5 additions & 0 deletions lib/mapstatic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ def self.options
require 'mapstatic/errors'
require 'mapstatic/version'
require 'mapstatic/conversion'
require 'mapstatic/bounding_box'
require 'mapstatic/map'
require 'mapstatic/tile'
require 'mapstatic/tile_source'
require 'mapstatic/renderer'
require 'mapstatic/painter'
require 'mapstatic/painter/null_painter'
require 'mapstatic/painter/line_string_painter'
92 changes: 92 additions & 0 deletions lib/mapstatic/bounding_box.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
module Mapstatic
class BoundingBox
attr_accessor :left, :right, :top, :bottom

def initialize(params={})
@left = params.fetch(:left)
@bottom = params.fetch(:bottom)
@right = params.fetch(:right)
@top = params.fetch(:top)
end

def to_a
[left, bottom, right, top]
end
alias_method :to_latlng_coordinates, :to_a

def to_xy_coordinates(zoom)
[
Conversion.lng_to_x(left, zoom),
Conversion.lat_to_y(bottom, zoom),
Conversion.lng_to_x(right, zoom),
Conversion.lat_to_y(top, zoom)
]
end

def center
lat = (bottom + top) / 2
lng = (left + right) / 2

{lat: lat, lng: lng}
end

def center=(lat:, lng:)
delta_lat = lat - center[:lat]
delta_lng = lng - center[:lng]

@left += delta_lng
@bottom += delta_lat
@right += delta_lng
@top += delta_lat
end

def width_at(zoom)
delta = Conversion.lng_to_x(right, zoom) - Conversion.lng_to_x(left, zoom)
(delta * Map::TILE_SIZE).abs
end

def height_at(zoom)
delta = Conversion.lat_to_y(top, zoom) - Conversion.lat_to_y(bottom, zoom)
(delta * Map::TILE_SIZE).abs
end

def fits_in?(other)
left >= other.left and right <= other.right and top <= other.top and bottom >= other.bottom
end

def contains?(other)
other.fits_in? self
end

def set_to(other)
@left = other.left
@right = other.right
@top = other.top
@bottom = other.bottom
end

def self.for(coordinates)
lngs = coordinates.map {|point| point[0]}
lats = coordinates.map {|point| point[1]}

left = lngs.min
bottom = lats.min
right = lngs.max
top = lats.max

BoundingBox.new top: top, bottom: bottom, left: left, right: right
end

def self.from(center_lat:, center_lng:, width:, height:, zoom:)
x = Conversion.lng_to_x(center_lng, zoom)
y = Conversion.lat_to_y(center_lat, zoom)

left = Conversion.x_to_lng( x - ( width / 2 ), zoom)
right = Conversion.x_to_lng( x + ( width / 2 ), zoom)
bottom = Conversion.y_to_lat( y + ( height / 2 ), zoom)
top = Conversion.y_to_lat( y - ( height / 2 ), zoom)

BoundingBox.new top: top, bottom: bottom, left: left, right: right
end
end
end
35 changes: 33 additions & 2 deletions lib/mapstatic/cli.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
require 'mapstatic'
require 'mapstatic/gpx_file'
require 'awesome_print'
require 'thor'
require 'json'

class Mapstatic::CLI < Thor

Expand Down Expand Up @@ -29,24 +31,53 @@ class Mapstatic::CLI < Thor
OpenStreetMap contributors).

You can generate a map using any tile set by passing the --provider option.

To draw a gpx track on top of the map, you can pass a file with --gpx:

$ mapstatic map uk.png --zoom=6 --width=320 --height=290 --gpx=file.gpx
LONGDESC

option :zoom, :required => true
option :zoom
option :provider, :default => 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
option :bbox
option :lat
option :lng
option :width, :default => 256
option :height, :default => 256
option :gpx
option :dryrun, :type => :boolean, :default => false

def map(filename)
params = Hash[options.map{|(k,v)| [k.to_sym,v]}]

if params[:bbox]
bbox = params[:bbox].split(",").map { |c| c.to_f }
params[:bbox] = bbox
end

map = Mapstatic::Map.new(params)

if options[:gpx]
gpx_file = Mapstatic::GpxFile.new options[:gpx]
geojson_data = gpx_file.geojson_data

# Drawing only one geojson feature is supported at the moment. So just pick
# the first one on the file.
first_track = geojson_data[:features].first
map.geojson = first_track
map.fit_bounds
end

map.render_map(filename) unless options[:dryrun]
ap map.metadata

metadata = {
map_bbox: map.viewport.to_a.join(','),
width: map.width.to_i,
height: map.height.to_i,
zoom: map.zoom
}

ap metadata
end

end
Loading