map_print 1.0.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 423a53002a18daf1de1ba8cd5aabdcc9c17fb112
4
- data.tar.gz: 49824e15480ccfffd1c89e48573c8e8fb7957ea7
3
+ metadata.gz: bcc0124c6e8b0ca5bae918c8306ff3057f8d400e
4
+ data.tar.gz: 0c47173c8d8a2079d54a6775ee738f3f9a50a233
5
5
  SHA512:
6
- metadata.gz: 8ee96b45449be505392177a1a893295e0c844728d48b762f28945c2cda30cb368ea48ce12d81dc30720adc740fa973125c70759fe3061592043b3e8c320ff069
7
- data.tar.gz: a3f083c06a7c3781c23362bde338748cadaf53cc9b0e057b212110ad56e2442f0452f88d10b293bb99a8cf972d2d36242b070f93dc1f59a68014b084b560c7f6
6
+ metadata.gz: 2a3fc9ee3d584924d37ac49a68319a9827f9c4b3a00718c5f77d81ee969b0ddacec7ba30626fca03fb04e527c68ee206c2cf3cc0fd5f0d4ff2a16f5c129f17da
7
+ data.tar.gz: 36f8e4882219e98149d3750d778e25292d277198a13b21c5e4b0f6c39d50486627105d2bba0bdfe1a6dc63967fb6dfee58892b3b854632f3f37df37dbbac1c26
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- map_print (1.0.1)
4
+ map_print (1.1.0)
5
5
  mini_magick (~> 4.3)
6
6
  parallel (~> 1.6)
7
7
  prawn (~> 2.0)
data/README.md CHANGED
@@ -27,7 +27,7 @@ Or install it yourself as:
27
27
 
28
28
  ### Executable
29
29
 
30
- `map_print print --south-west="-35.026862,-58.425003" --north-east="-29.980172,-52.959305" --zoom="10" --output="output.png"`
30
+ `map_print print --south-west="-35.026862,-58.425003" --north-east="-29.980172,-52.959305" --width=500 --height=800 --zoom="10" --output="output.png"`
31
31
 
32
32
  Indicating southwest and northeast to determine the bounding box. Set the zoom at which the tiles should be requested.
33
33
 
@@ -210,7 +210,14 @@ map_configuration = {
210
210
  padding: {top: 5, right: 5, bottom: 5, left: 5},
211
211
  bar_height: 10,
212
212
  background_color: 'black',
213
- background_opacity: 0.4
213
+ background_opacity: 0.4,
214
+ text_style: {
215
+ fill_color: '#ffffff',
216
+ color: '#000000',
217
+ font: 'Arial',
218
+ pointsize: '16',
219
+ gravity: 'NorthWest'
220
+ }
214
221
  }
215
222
  }
216
223
  ```
data/bin/map_print CHANGED
@@ -10,8 +10,10 @@ class MapPrintCommand < Thor
10
10
 
11
11
  method_option :south_west, type: :string, required: true
12
12
  method_option :north_east, type: :string, required: true
13
- method_option :output, type: :string, required: true
13
+ method_option :width, type: :numeric, required: true
14
+ method_option :height, type: :numeric, required: true
14
15
  method_option :zoom, type: :numeric, default: 10
16
+ method_option :output, type: :string, required: true
15
17
 
16
18
  method_option :provider, type: :string, default: 'osm',
17
19
  enum: ['osm', 'bing']
@@ -25,8 +27,11 @@ class MapPrintCommand < Thor
25
27
  south_west = MapPrint::LatLng.new(*south_west_coordinate)
26
28
  north_east = MapPrint::LatLng.new(*north_east_coordinate)
27
29
 
30
+ png_options = {height: options[:height], width: options[:width]}
31
+
28
32
  map_options = {
29
33
  format: 'png',
34
+ png_options: png_options,
30
35
  map: {
31
36
  sw: {
32
37
  lat: south_west.lat,
@@ -38,30 +38,33 @@ module MapPrint
38
38
  end
39
39
  end
40
40
 
41
- def feature(geometry, properties={})
41
+ def validate_feature(geometry, properties)
42
42
  raise NoGeometryPresent.new("No geometry present for this feature") if geometry.nil?
43
43
  case geometry['type']
44
+ when 'Point'
45
+ if properties.nil? || properties['image'].nil?
46
+ raise NoPointImage.new("Missing image in point geometry")
47
+ end
48
+ when 'MultiPoint', 'MultiLineString', 'MultiPolygon', 'GeometryCollection'
49
+ raise FeatureNotImplemented.new("Please consider contributing!")
50
+ else
51
+ Logger.warn "Feature type '#{geometry['type']}' not implemented!"
52
+ end
53
+ end
54
+
55
+ def feature(geometry, properties={})
56
+ validate_feature(geometry, properties)
57
+ case geometry['type']
44
58
  when 'Feature'
45
59
  feature(geometry['geometry'], geometry['properties'])
46
60
  when 'FeatureCollection'
47
61
  feature_collection(geometry['features'])
48
62
  when 'Point'
49
- raise NoPointImage.new("Missing image in point geometry") unless properties && properties['image']
50
63
  point(geometry, properties['image'])
51
64
  when 'LineString'
52
65
  line_string(geometry, properties)
53
66
  when 'Polygon'
54
67
  polygon(geometry, properties)
55
- when 'MultiPoint'
56
- raise FeatureNotImplemented.new("Please consider contributing!")
57
- when 'MultiLineString'
58
- raise FeatureNotImplemented.new("Please consider contributing!")
59
- when 'MultiPolygon'
60
- raise FeatureNotImplemented.new("Please consider contributing!")
61
- when 'GeometryCollection'
62
- raise FeatureNotImplemented.new("Please consider contributing!")
63
- else
64
- Logger.warn "Feature type '#{geometry['type']}' not implemented!"
65
68
  end
66
69
  rescue GeoJSONHandlerError => ex
67
70
  Logger.warn ex
@@ -77,7 +80,7 @@ module MapPrint
77
80
  x = get_x(point['coordinates'][0])
78
81
  y = get_y(point['coordinates'][1])
79
82
 
80
- if 0 <= x && x <= @width && 0 <= y && y <= @height
83
+ if point_inside_map?(x, y)
81
84
  point_image = MiniMagick::Image.open(image_path)
82
85
  x -= point_image.width / 2
83
86
  y -= point_image.height / 2
@@ -92,17 +95,7 @@ module MapPrint
92
95
  end
93
96
 
94
97
  def line_string(geometry, properties)
95
- properties ||= {}
96
- coords = geometry['coordinates']
97
- coords = coords.first if coords.first.first.is_a?(Array)
98
- points = coords.map do |coord|
99
- x = get_x(coord[0])
100
- y = get_y(coord[1])
101
- if 0 <= x && x <= @width && 0 <= y && y <= @height
102
- Logger.warn "Line coordinate outside map's boundaries!\ngeometry: #{geometry.inspect}\nproperties: #{properties.inspect}"
103
- end
104
- "#{x},#{y}"
105
- end
98
+ points = generate_drawable_points(geometry, properties)
106
99
 
107
100
  draw_command = (0..(points.length - 2)).map do |i|
108
101
  "line #{points[i]} #{points[i+1]}"
@@ -115,17 +108,7 @@ module MapPrint
115
108
  end
116
109
 
117
110
  def polygon(geometry, properties)
118
- properties ||= {}
119
- coords = geometry['coordinates']
120
- coords = coords.first if coords.first.first.is_a?(Array)
121
- points = coords.map do |coord|
122
- x = get_x(coord[0])
123
- y = get_y(coord[1])
124
- if 0 <= x && x <= @width && 0 <= y && y <= @height
125
- Logger.warn "Polygon coordinate outside map's boundaries!\ngeometry: #{geometry.inspect}\nproperties: #{properties.inspect}"
126
- end
127
- "#{x},#{y}"
128
- end
111
+ points = generate_drawable_points(geometry, properties)
129
112
 
130
113
  @image.combine_options do |c|
131
114
  c.density 300
@@ -133,20 +116,29 @@ module MapPrint
133
116
  end
134
117
  end
135
118
 
136
- def draw_options(properties, line=true)
119
+ def stroke_options(properties)
137
120
  options = ''
138
121
  if properties['stroke'] || properties['stroke'].nil?
139
122
  options += "stroke #{properties['color'] || '#0033ff'} "
140
123
  options += "stroke-width #{properties['weight'] || 5} "
141
124
  options += "stroke-opacity #{properties['opacity'] || 0.5} "
142
125
  end
126
+ options
127
+ end
143
128
 
144
- if properties['fill'] || (!line && properties['fill'].nil?)
129
+ def fill_options(properties, line)
130
+ options = ''
131
+ if properties['fill'] != false || !line
145
132
  options += "fill #{properties['fillColor'] || '#0033ff'} "
146
133
  options += "fill-opacity #{properties['fillOpacity'] || 0.2} "
147
134
  options += "fill-rule #{properties['fillRule'] || 'evenodd'} "
148
135
  end
136
+ options
137
+ end
149
138
 
139
+ def draw_options(properties, line=true)
140
+ options = stroke_options(properties)
141
+ options += fill_options(properties, line)
150
142
  options += "stroke-dasharray #{properties['dashArray']} " if properties['dashArray']
151
143
  options += "stroke-linecap #{properties['lineCap']} " if properties['lineCap']
152
144
  options += "stroke-linejoin #{properties['lineJoin']} " if properties['lineJoin']
@@ -160,5 +152,27 @@ module MapPrint
160
152
  def get_y(lat)
161
153
  @height * (@top_lat - lat) / @total_lat;
162
154
  end
155
+
156
+ def point_inside_map?(x, y)
157
+ 0 <= x && x <= @width && 0 <= y && y <= @height
158
+ end
159
+
160
+ def consider_outside_boundaries(x, y, geometry, properties)
161
+ if !point_inside_map?(x, y)
162
+ Logger.warn "Coordinate outside map's boundaries!\ngeometry: #{geometry.inspect}\nproperties: #{properties.inspect}"
163
+ end
164
+ end
165
+
166
+ def generate_drawable_points(geometry, properties)
167
+ properties ||= {}
168
+ coords = geometry['coordinates']
169
+ coords = coords.first if coords.first.first.is_a?(Array)
170
+ coords.map do |coord|
171
+ x = get_x(coord[0])
172
+ y = get_y(coord[1])
173
+ consider_outside_boundaries(x, y, geometry, properties)
174
+ "#{x},#{y}"
175
+ end
176
+ end
163
177
  end
164
178
  end
@@ -6,12 +6,21 @@ module MapPrint
6
6
  include PngHandlers::Texts
7
7
  include Validations::Size
8
8
 
9
+ OVERFLOW = {
10
+ expand: 'expand',
11
+ compact: 'compact',
12
+ hidden: 'hidden'
13
+ }
14
+ VERTICAL = 'vertical'
15
+ HORIZONTAL = 'horizontal'
16
+
9
17
  def initialize(legend)
10
18
  @legend = legend
11
19
  validate_data!
20
+ overflow_option_adjustments
12
21
  @x_step = @legend[:size][:width] / @legend[:columns]
13
22
  @y_step = @legend[:size][:height] / @legend[:rows]
14
- @elements_in_block = @legend[:orientation] == 'vertical' ? @legend[:rows] : @legend[:columns]
23
+ @elements_in_block = @legend[:orientation] == VERTICAL ? @legend[:rows] : @legend[:columns]
15
24
  @legend[:textbox_style] ||= {}
16
25
 
17
26
  if @legend[:textbox_size]
@@ -73,7 +82,7 @@ module MapPrint
73
82
  end
74
83
 
75
84
  def get_next_x_y(x, y, z)
76
- if @legend[:orientation] == 'vertical'
85
+ if @legend[:orientation] == VERTICAL
77
86
  y, x = next_step(y, x, @y_step, @x_step, z)
78
87
  else
79
88
  x, y = next_step(x, y, @x_step, @y_step, z)
@@ -92,5 +101,61 @@ module MapPrint
92
101
 
93
102
  return small_step_value, big_step_value
94
103
  end
104
+
105
+ def overflow_hidden?
106
+ @legend[:overflow].nil? || @legend[:overflow].downcase == OVERFLOW[:hidden]
107
+ end
108
+
109
+ def overflow_expand?
110
+ @legend[:overflow].downcase == OVERFLOW[:expand]
111
+ end
112
+
113
+ def overflow_compact?
114
+ @legend[:overflow].downcase == OVERFLOW[:compact]
115
+ end
116
+
117
+ def vertical_orientation?
118
+ @legend[:orientation] == VERTICAL
119
+ end
120
+
121
+ def horizontal_orientation?
122
+ @legend[:orientation] == HORIZONTAL
123
+ end
124
+
125
+ def available_legend_spots
126
+ @legend[:columns] * @legend[:rows]
127
+ end
128
+
129
+ def overflow_option_adjustments
130
+ return unless @legend[:elements].size > available_legend_spots
131
+ case
132
+ when overflow_hidden?
133
+ @legend[:elements] = @legend[:elements][0..(available_legend_spots-1)]
134
+ when overflow_expand?
135
+ expand_adjustments
136
+ when overflow_compact?
137
+ compact_adjustments
138
+ end
139
+ end
140
+
141
+ def expand_adjustments
142
+ if vertical_orientation?
143
+ column_width = @legend[:size][:width] / @legend[:columns]
144
+ compact_adjustments
145
+ @legend[:size][:width] = @legend[:columns] * column_width
146
+ elsif horizontal_orientation?
147
+ row_height = @legend[:size][:height] / @legend[:rows]
148
+ compact_adjustments
149
+ @legend[:size][:height] = @legend[:rows] * row_height
150
+ end
151
+ end
152
+
153
+ def compact_adjustments
154
+ if vertical_orientation?
155
+ @legend[:columns] = (@legend[:elements].size / @legend[:rows].to_f).ceil
156
+ elsif horizontal_orientation?
157
+ @legend[:rows] = (@legend[:elements].size / @legend[:columns].to_f).ceil
158
+ end
159
+ end
95
160
  end
96
161
  end
@@ -19,12 +19,12 @@ module MapPrint
19
19
 
20
20
  scalebar_image = @context.print_scalebar
21
21
  if scalebar_image
22
- @pdf.image scalebar_image.path, at: [@context.scalebar[:position][:x], @pdf.bounds.top - @context.scalebar[:position][:y]]
22
+ print_image(scalebar_image.path, @context.scalebar[:position])
23
23
  end
24
24
 
25
25
  legend_image = @context.print_legend
26
26
  if legend_image
27
- @pdf.image legend_image.path, at: [@context.legend[:position][:x], @pdf.bounds.top - @context.legend[:position][:y]]
27
+ print_image(legend_image.path, @context.legend[:position])
28
28
  end
29
29
 
30
30
  @pdf.render_file(@context.output_path)
@@ -42,5 +42,9 @@ module MapPrint
42
42
  position = @context.map[:position] || {}
43
43
  @pdf.image map_image.path, at: [position[:x] || 0, @pdf.bounds.top - (position[:y] || 0)], fit: size.values
44
44
  end
45
+
46
+ def print_image(image_path, position)
47
+ @pdf.image image_path, at: [position[:x], @pdf.bounds.top - position[:y]]
48
+ end
45
49
  end
46
50
  end
@@ -54,20 +54,17 @@ module MapPrint
54
54
  quarter = (size[:width] - @padding_left - @padding_right) / 4
55
55
 
56
56
  y_position = size[:height] - (@scalebar[:bar_height] || 10) - @padding_bottom
57
+ orig_y = size[:height] - @padding_bottom
57
58
  image.combine_options do |c|
58
59
  c.density 300
59
60
  c.stroke 'black'
60
- c.fill 'white'
61
- c.draw "rectangle #{@padding_left},#{size[:height] - @padding_bottom} #{@padding_left + quarter},#{y_position}"
62
- c.fill 'black'
63
- c.draw "rectangle #{@padding_left + quarter},#{size[:height] - @padding_bottom} #{@padding_left + 2*quarter},#{y_position}"
64
- c.fill 'white'
65
- c.draw "rectangle #{@padding_left + 2*quarter},#{size[:height] - @padding_bottom} #{@padding_left + 3*quarter},#{y_position}"
66
- c.fill 'black'
67
- c.draw "rectangle #{@padding_left + 3*quarter},#{size[:height] - @padding_bottom} #{@padding_left + 4*quarter},#{y_position}"
61
+ (0..3).each do |i|
62
+ c.fill (i % 2 == 0 ? 'white' : 'black')
63
+ c.draw "rectangle #{@padding_left + i*quarter},#{orig_y} #{@padding_left + (i+1)*quarter},#{y_position}"
64
+ end
68
65
  end
69
66
 
70
- text_options = { pointsize: 4, gravity: 'NorthWest' }
67
+ text_options = { pointsize: 4, gravity: 'NorthWest' }.merge(@scalebar[:text_style] || {})
71
68
  draw_text(image, "0", "#{@padding_left},#{@padding_top}", text_options)
72
69
  draw_text(image, (pixels_for_distance/4).round(-2).to_s, "#{-quarter + @padding_left - @padding_right},#{@padding_top}", text_options.merge(gravity: 'North'))
73
70
  draw_text(image, (pixels_for_distance/2).round(-2).to_s, "#{@padding_left - @padding_right},#{@padding_top}", text_options.merge(gravity: 'North'))
@@ -1,3 +1,3 @@
1
1
  module MapPrint
2
- VERSION = '1.0.1'
2
+ VERSION = '1.1.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: map_print
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Fast
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-25 00:00:00.000000000 Z
11
+ date: 2016-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler