simpler-tiles 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +2 -0
  3. data/LICENSE +19 -0
  4. data/README +22 -0
  5. data/Rakefile +71 -0
  6. data/doc/SimplerTiles/Bounds.html +506 -0
  7. data/doc/SimplerTiles/Layer.html +593 -0
  8. data/doc/SimplerTiles/Map.html +2081 -0
  9. data/doc/SimplerTiles/PP.html +204 -0
  10. data/doc/SimplerTiles/Query.html +521 -0
  11. data/doc/SimplerTiles/Style.html +577 -0
  12. data/doc/SimplerTiles.html +167 -0
  13. data/doc/_index.html +188 -0
  14. data/doc/class_list.html +47 -0
  15. data/doc/css/common.css +1 -0
  16. data/doc/css/full_list.css +55 -0
  17. data/doc/css/style.css +322 -0
  18. data/doc/file.README.html +89 -0
  19. data/doc/file_list.html +49 -0
  20. data/doc/frames.html +13 -0
  21. data/doc/index.html +89 -0
  22. data/doc/js/app.js +205 -0
  23. data/doc/js/full_list.js +173 -0
  24. data/doc/js/jquery.js +16 -0
  25. data/doc/method_list.html +390 -0
  26. data/doc/top-level-namespace.html +105 -0
  27. data/ext/simpler_tiles/bounds.c +90 -0
  28. data/ext/simpler_tiles/bounds.h +17 -0
  29. data/ext/simpler_tiles/depend +7 -0
  30. data/ext/simpler_tiles/extconf.rb +42 -0
  31. data/ext/simpler_tiles/layer.c +93 -0
  32. data/ext/simpler_tiles/layer.h +16 -0
  33. data/ext/simpler_tiles/map.c +338 -0
  34. data/ext/simpler_tiles/map.h +17 -0
  35. data/ext/simpler_tiles/query.c +87 -0
  36. data/ext/simpler_tiles/query.h +17 -0
  37. data/ext/simpler_tiles/simpler_tiles.c +16 -0
  38. data/ext/simpler_tiles/simpler_tiles.h +25 -0
  39. data/ext/simpler_tiles/style.c +106 -0
  40. data/ext/simpler_tiles/style.h +17 -0
  41. data/index.erb +459 -0
  42. data/index.html +439 -0
  43. data/lib/simpler_tiles/bounds.rb +19 -0
  44. data/lib/simpler_tiles/layer.rb +25 -0
  45. data/lib/simpler_tiles/map.rb +55 -0
  46. data/lib/simpler_tiles/mixins/pp.rb +13 -0
  47. data/lib/simpler_tiles/query.rb +28 -0
  48. data/lib/simpler_tiles/style.rb +19 -0
  49. data/lib/simpler_tiles/version.rb +4 -0
  50. data/lib/simpler_tiles.rb +13 -0
  51. data/simpler-tiles-logo.png +0 -0
  52. data/simpler-tiles.gemspec +30 -0
  53. data/test/helper.rb +8 -0
  54. data/test/test_map.rb +67 -0
  55. data/test/test_simpler_tiles.rb +26 -0
  56. metadata +199 -0
data/index.html ADDED
@@ -0,0 +1,439 @@
1
+
2
+ <!doctype html>
3
+ <html>
4
+ <head>
5
+ <title>Simpler Tiles</title>
6
+ <!--
7
+ +-----------------------------+
8
+ | / ~|
9
+ | ---------- /|
10
+ | Simpler / --------- |
11
+ | / ~ / ** |
12
+ | / / **** |
13
+ | ---- ~ / ****** |
14
+ | / ~~ -- ******* |
15
+ | / / ***** |
16
+ | / / |
17
+ | / ~~ / Tiles |
18
+ |- / |
19
+ | ~~~ / |
20
+ +-----------------------------+
21
+ -->
22
+ <meta charset="utf-8">
23
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
24
+ <style>
25
+ /* reset */
26
+ div, html, body {
27
+ margin: 0;
28
+ padding: 0;
29
+ border: 0;
30
+ vertical-align: baseline;
31
+ }
32
+
33
+ ul { list-style: none; padding-left: 10px;}
34
+ li { margin-bottom: 1em; }
35
+ /* text styles */
36
+ body {
37
+ font-family: "Helvetica Nueue", Helvetica, sans-serif;
38
+ font-size: 14px;
39
+ line-height: 1.7em;
40
+ margin-left: auto;
41
+ margin-right: auto;
42
+ width: 600px;
43
+ padding: 20px;
44
+ }
45
+ p, li {
46
+ width: 600px;
47
+ margin: 0px 0px 1em;
48
+ }
49
+
50
+ h1, h2, h3 {
51
+ text-rendering: optimizeLegibility;
52
+ margin-left: -5px;
53
+ }
54
+
55
+ h4 {
56
+ margin: 0px;
57
+ margin-top: 30px;
58
+ margin-left: -5px;
59
+ font-weight: normal;
60
+ }
61
+
62
+ h4 code {
63
+ padding: 4px;
64
+ background-color: #e6f3ff;
65
+ }
66
+
67
+ ol {
68
+ padding-left: 0px;
69
+ }
70
+
71
+ code, pre, tt { font-family: Monaco, monospace; font-size: 12px; }
72
+ tt { border:1px solid #efefef; padding: 2px;}
73
+ dd { margin-left: 1em; }
74
+ a { color: black; }
75
+ a:hover { text-decoration: none; }
76
+ pre {
77
+ padding-left: 10px;
78
+ font-size: 12px;
79
+ border-left: 5px solid #efefef;
80
+ line-height: 1.3;
81
+ }
82
+
83
+ hr {
84
+ border: 0;
85
+ border-top: 1px solid #efefef;
86
+ height: 1px;
87
+ }
88
+
89
+ /* styles stolen from docco */
90
+ body .hll { background-color: #ffffcc }
91
+ body .c { color: #408080; font-style: italic } /* Comment */
92
+ body .err { border: 1px solid #FF0000 } /* Error */
93
+ body .k { color: #954121 } /* Keyword */
94
+ body .o { color: #666666 } /* Operator */
95
+ body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
96
+ body .cp { color: #BC7A00 } /* Comment.Preproc */
97
+ body .c1 { color: #408080; font-style: italic } /* Comment.Single */
98
+ body .cs { color: #408080; font-style: italic } /* Comment.Special */
99
+ body .gd { color: #A00000 } /* Generic.Deleted */
100
+ body .ge { font-style: italic } /* Generic.Emph */
101
+ body .gr { color: #FF0000 } /* Generic.Error */
102
+ body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
103
+ body .gi { color: #00A000 } /* Generic.Inserted */
104
+ body .go { color: #808080 } /* Generic.Output */
105
+ body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
106
+ body .gs { font-weight: bold } /* Generic.Strong */
107
+ body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
108
+ body .gt { color: #0040D0 } /* Generic.Traceback */
109
+ body .kc { color: #954121 } /* Keyword.Constant */
110
+ body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
111
+ body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
112
+ body .kp { color: #954121 } /* Keyword.Pseudo */
113
+ body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
114
+ body .kt { color: #B00040 } /* Keyword.Type */
115
+ body .m { color: #666666 } /* Literal.Number */
116
+ body .s { color: #219161 } /* Literal.String */
117
+ body .na { color: #7D9029 } /* Name.Attribute */
118
+ body .nb { color: #954121 } /* Name.Builtin */
119
+ body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
120
+ body .no { color: #880000 } /* Name.Constant */
121
+ body .nd { color: #AA22FF } /* Name.Decorator */
122
+ body .ni { color: #999999; font-weight: bold } /* Name.Entity */
123
+ body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
124
+ body .nf { color: #0000FF } /* Name.Function */
125
+ body .nl { color: #A0A000 } /* Name.Label */
126
+ body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
127
+ body .nt { color: #954121; font-weight: bold } /* Name.Tag */
128
+ body .nv { color: #19469D } /* Name.Variable */
129
+ body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
130
+ body .w { color: #bbbbbb } /* Text.Whitespace */
131
+ body .mf { color: #666666 } /* Literal.Number.Float */
132
+ body .mh { color: #666666 } /* Literal.Number.Hex */
133
+ body .mi { color: #666666 } /* Literal.Number.Integer */
134
+ body .mo { color: #666666 } /* Literal.Number.Oct */
135
+ body .sb { color: #219161 } /* Literal.String.Backtick */
136
+ body .sc { color: #219161 } /* Literal.String.Char */
137
+ body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
138
+ body .s2 { color: #219161 } /* Literal.String.Double */
139
+ body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
140
+ body .sh { color: #219161 } /* Literal.String.Heredoc */
141
+ body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
142
+ body .sx { color: #954121 } /* Literal.String.Other */
143
+ body .sr { color: #BB6688 } /* Literal.String.Regex */
144
+ body .s1 { color: #219161 } /* Literal.String.Single */
145
+ body .ss { color: #19469D } /* Literal.String.Symbol */
146
+ body .bp { color: #954121 } /* Name.Builtin.Pseudo */
147
+ body .vc { color: #19469D } /* Name.Variable.Class */
148
+ body .vg { color: #19469D } /* Name.Variable.Global */
149
+ body .vi { color: #19469D } /* Name.Variable.Instance */
150
+ body .il { color: #666666 } /* Literal.Number.Integer.Long */
151
+ </style>
152
+ </head>
153
+ <body>
154
+ <img src="simpler-tiles-logo.png">
155
+ <p>
156
+ <a href="http://github.com/propublica/simpler-tiles">Simpler Tiles</a>
157
+ is a library of ruby bindings for
158
+ <a href="http://propublica.github.com/simple-tiles/">Simple Tiles</a>, a
159
+ GIS image generation library. It allows you to generate PNG based map
160
+ images without having to dip into straight C and easily connects with
161
+ ActiveRecord. It can display any vector data that
162
+ <a href="http://www.gdal.org/ogr/ogr_formats.html">OGR</a> can read.
163
+ </p>
164
+
165
+ <p>
166
+ The source is at <a href="http://github.com/propublica/simpler-tiles">Github</a>.
167
+ You can install the gem with:
168
+ <pre>
169
+ $ gem install simpler-tiles
170
+ </pre>
171
+ </p>
172
+
173
+ <p>
174
+ The api docs are <a href="doc/index.html">here</a>, and if you have
175
+ comments or questions head on over to <tt>#newsapps</tt> or <tt>#propublica</tt>
176
+ on Freenode, or post them in the github issue
177
+ <a href="https://github.com/propublica/simpler-tiles/issues?sort=created&direction=desc&state=open">tracker</a>.
178
+ </p>
179
+
180
+ <h2>Dependencies</h2>
181
+
182
+ <p>
183
+ Simpler Tiles depends on <a href="http://propublica.github.com/simple-tiles/">Simple Tiles</a>, <a href="http://www.gdal.org/ogr/">OGR</a>, <a href="http://cairographics.org/">Cairo</a> and <a href="http://www.pango.org/">Pango</a>. You can find
184
+ installation instructions for these libraries in the
185
+ <a href="http://propublica.github.com/simple-tiles/#dependencies">Simple Tiles
186
+ documentation</a>.
187
+ </p>
188
+
189
+ <h2>Overview</h2>
190
+
191
+ <p>
192
+ Simpler Tiles contains a hierarchy of objects:
193
+ </p>
194
+ <ul>
195
+ <li>
196
+ <tt><a href="doc/SimplerTiles/Map.html">SimplerTiles::Map</a></tt>: wraps
197
+ the <tt><a href="http://propublica.github.com/simple-tiles/#maps">simplet_map_t</a></tt>
198
+ C structure and contains projection information, <tt>SimplerTiles::Bounds</tt>
199
+ and a list of <tt>SimplerTiles::Layer</tt> objects. If you are using ActiveRecord
200
+ you can connect to and query your database backend by calling the
201
+ <tt>ar_layer</tt> method.
202
+ </li>
203
+ <li>
204
+ <tt><a href="doc/SimplerTiles/Bounds.html">SimplerTiles::Bounds</a></tt>: wraps
205
+ the <tt><a href="http://propublica.github.com/simple-tiles/#bounds">simplet_bounds_t</a></tt>
206
+ C structure and specifies the limit of the map in spatial coordinates.
207
+ </li>
208
+ <li>
209
+ <tt><a href="doc/SimplerTiles/Map.html">SimplerTiles::Layer</a></tt>: wraps
210
+ the <tt><a href="http://propublica.github.com/simple-tiles/#layers">simplet_layer_t</a></tt>
211
+ C structure and contains an OGR connection string for a particular data source,
212
+ and contains a list of <tt>SimplerTiles::Query</tt> objects.
213
+ </li>
214
+ <li>
215
+ <tt><a href="doc/SimplerTiles/Query.html">SimplerTiles::Query</a></tt>: wraps
216
+ the <tt><a href="http://propublica.github.com/simple-tiles/#queries">simplet_query_t</a></tt>
217
+ C structure and contains an OGR SQL string to filter its parent layer's
218
+ data source.
219
+ </li>
220
+ <li>
221
+ <tt><a href="doc/SimplerTiles/Style.html">SimplerTiles::Style</a></tt>: wraps
222
+ the <tt><a href="http://propublica.github.com/simple-tiles/#style">simplet_style_t</a></tt>
223
+ C structure and specifies a Simple Tiles
224
+ <a href="http://propublica.github.com/simple-tiles/#styles">style declaration</a>.
225
+ </li>
226
+ </ul>
227
+
228
+ <p>
229
+ As an example of how this fits together, here is a script that generates
230
+ the Simpler Tiles logo (full repository
231
+ <a href="https://github.com/thejefflarson/simpler-tiles-contours">here</a>):
232
+ </p>
233
+
234
+ <div class="highlight"><pre><span class="nb">require</span> <span class="s1">&#39;rubygems&#39;</span>
235
+ <span class="nb">require</span> <span class="s1">&#39;simpler_tiles&#39;</span>
236
+
237
+ <span class="no">ROOT</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">expand_path</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">))</span>
238
+
239
+ <span class="n">map</span> <span class="o">=</span> <span class="no">SimplerTiles</span><span class="o">::</span><span class="no">Map</span><span class="o">.</span><span class="n">new</span> <span class="k">do</span> <span class="o">|</span><span class="n">m</span><span class="o">|</span>
240
+ <span class="n">m</span><span class="o">.</span><span class="n">srs</span> <span class="o">=</span> <span class="s2">&quot;EPSG:3083&quot;</span>
241
+ <span class="n">m</span><span class="o">.</span><span class="n">bgcolor</span> <span class="o">=</span> <span class="s2">&quot;#ffffff&quot;</span>
242
+ <span class="n">m</span><span class="o">.</span><span class="n">width</span> <span class="o">=</span> <span class="mi">423</span>
243
+ <span class="n">m</span><span class="o">.</span><span class="n">height</span> <span class="o">=</span> <span class="mi">260</span>
244
+ <span class="n">m</span><span class="o">.</span><span class="n">set_bounds</span><span class="p">(</span><span class="o">-</span><span class="mi">585080</span><span class="o">.</span><span class="mi">885134</span><span class="p">,</span> <span class="mi">6849466</span><span class="o">.</span><span class="mi">721081</span><span class="p">,</span> <span class="mi">4161303</span><span class="o">.</span><span class="mi">603672</span><span class="p">,</span> <span class="mi">9587780</span><span class="o">.</span><span class="mi">816356</span><span class="p">)</span>
245
+
246
+ <span class="no">Dir</span><span class="o">[</span><span class="s2">&quot;</span><span class="si">#{</span><span class="no">ROOT</span><span class="si">}</span><span class="s2">/data/*.shp&quot;</span><span class="o">].</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">shp</span><span class="o">|</span>
247
+ <span class="n">m</span><span class="o">.</span><span class="n">layer</span> <span class="n">shp</span> <span class="k">do</span> <span class="o">|</span><span class="n">l</span><span class="o">|</span>
248
+ <span class="n">l</span><span class="o">.</span><span class="n">query</span> <span class="s2">&quot;select * from &#39;</span><span class="si">#{</span><span class="no">File</span><span class="o">.</span><span class="n">basename</span> <span class="n">shp</span><span class="p">,</span> <span class="s1">&#39;.shp&#39;</span><span class="si">}</span><span class="s2">&#39;&quot;</span> <span class="k">do</span> <span class="o">|</span><span class="n">q</span><span class="o">|</span>
249
+ <span class="n">q</span><span class="o">.</span><span class="n">styles</span> <span class="s2">&quot;stroke&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;#111111&quot;</span><span class="p">,</span>
250
+ <span class="s2">&quot;line-join&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;round&quot;</span><span class="p">,</span>
251
+ <span class="s2">&quot;weight&quot;</span> <span class="o">=&gt;</span> <span class="s2">&quot;0.1&quot;</span>
252
+ <span class="k">end</span>
253
+ <span class="k">end</span>
254
+ <span class="k">end</span>
255
+ <span class="k">end</span>
256
+
257
+ <span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">#{</span><span class="no">ROOT</span><span class="si">}</span><span class="s2">/out.png&quot;</span><span class="p">,</span> <span class="s1">&#39;w&#39;</span><span class="p">)</span> <span class="p">{</span><span class="o">|</span><span class="n">f</span><span class="o">|</span> <span class="n">f</span><span class="o">.</span><span class="n">write</span> <span class="n">map</span><span class="o">.</span><span class="n">to_png</span> <span class="p">}</span>
258
+ </pre></div>
259
+
260
+
261
+
262
+ <h2>A Basic Tile Server</h2>
263
+
264
+ <p>
265
+ Simpler Tiles was designed to make <a href="http://wiki.openstreetmap.org/wiki/Slippy_Map">slippy maps</a>. The following is a basic tile
266
+ server using <a href="http://sinatrarb.com">Sinatra</a>. It will open display any shapefile on your hard drive
267
+ by visiting a url like: <a href="">http://localhost:4567/shape/path/to/shapefile.shp</a>
268
+ </p>
269
+
270
+ <div class="highlight"><pre><span class="nb">require</span> <span class="s1">&#39;rubygems&#39;</span>
271
+ <span class="nb">require</span> <span class="s1">&#39;sinatra&#39;</span>
272
+ <span class="nb">require</span> <span class="s1">&#39;simpler_tiles&#39;</span>
273
+
274
+ <span class="c1"># Grab the user&#39;s home directory</span>
275
+ <span class="no">ROOT</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">expand_path</span><span class="p">(</span><span class="s2">&quot;~&quot;</span><span class="p">)</span>
276
+
277
+ <span class="c1"># Set up a route that will grab the path to a shapefile and render the</span>
278
+ <span class="c1"># index template below.</span>
279
+ <span class="n">get</span> <span class="s1">&#39;/shape/*&#39;</span> <span class="k">do</span>
280
+ <span class="n">erb</span> <span class="ss">:index</span>
281
+ <span class="k">end</span>
282
+
283
+ <span class="c1"># Set up the tile url to capture x, y, z coordinates for slippy tile generation</span>
284
+ <span class="n">get</span> <span class="s1">&#39;/tiles/*/:x/:y/:z.png&#39;</span> <span class="k">do</span>
285
+
286
+ <span class="c1"># Let the browser know we are sending a png</span>
287
+ <span class="n">content_type</span> <span class="s1">&#39;image/png&#39;</span>
288
+
289
+ <span class="c1"># Create a Map object</span>
290
+ <span class="n">map</span> <span class="o">=</span> <span class="no">SimplerTiles</span><span class="o">::</span><span class="no">Map</span><span class="o">.</span><span class="n">new</span> <span class="k">do</span> <span class="o">|</span><span class="n">m</span><span class="o">|</span>
291
+ <span class="c1"># Set the background color to black</span>
292
+ <span class="n">m</span><span class="o">.</span><span class="n">bgcolor</span> <span class="o">=</span> <span class="s2">&quot;#000000&quot;</span>
293
+
294
+ <span class="c1"># Set the slippy map parameters from the url</span>
295
+ <span class="n">m</span><span class="o">.</span><span class="n">slippy</span> <span class="n">params</span><span class="o">[</span><span class="ss">:x</span><span class="o">].</span><span class="n">to_i</span><span class="p">,</span> <span class="n">params</span><span class="o">[</span><span class="ss">:y</span><span class="o">].</span><span class="n">to_i</span><span class="p">,</span> <span class="n">params</span><span class="o">[</span><span class="ss">:z</span><span class="o">].</span><span class="n">to_i</span>
296
+
297
+ <span class="c1"># Add a layer based on the parameters in the URL</span>
298
+ <span class="n">m</span><span class="o">.</span><span class="n">layer</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="no">ROOT</span><span class="p">,</span> <span class="n">params</span><span class="o">[</span><span class="ss">:splat</span><span class="o">].</span><span class="n">first</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">l</span><span class="o">|</span>
299
+
300
+ <span class="c1"># Grab all of the data from the shapefile</span>
301
+ <span class="n">l</span><span class="o">.</span><span class="n">query</span> <span class="s2">&quot;select * from &#39;</span><span class="si">#{</span><span class="no">File</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">params</span><span class="o">[</span><span class="ss">:splat</span><span class="o">].</span><span class="n">first</span><span class="p">,</span> <span class="s1">&#39;.shp&#39;</span><span class="p">)</span><span class="si">}</span><span class="s2">&#39;&quot;</span> <span class="k">do</span> <span class="o">|</span><span class="n">q</span><span class="o">|</span>
302
+
303
+ <span class="c1"># Add a style for stroke, fill, weight and set the line-join to be round</span>
304
+ <span class="n">q</span><span class="o">.</span><span class="n">styles</span> <span class="s1">&#39;stroke&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;#002240&#39;</span><span class="p">,</span>
305
+ <span class="s1">&#39;weight&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;1&#39;</span><span class="p">,</span>
306
+ <span class="s1">&#39;line-join&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;round&#39;</span><span class="p">,</span>
307
+ <span class="s1">&#39;fill&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;#ffffff&#39;</span>
308
+ <span class="k">end</span>
309
+ <span class="k">end</span>
310
+ <span class="k">end</span>
311
+
312
+ <span class="c1"># Finally, render the map and ship it off</span>
313
+ <span class="n">map</span><span class="o">.</span><span class="n">to_png</span>
314
+ <span class="k">end</span>
315
+
316
+ <span class="c1"># A simple inline template for the map</span>
317
+ <span class="cp">__END__</span>
318
+
319
+ <span class="cp">@@index</span>
320
+ <span class="cp">&lt;!doctype html&gt;</span>
321
+ <span class="cp">&lt;html&gt;</span>
322
+ <span class="cp">&lt;head&gt;</span>
323
+ <span class="cp"> &lt;script src=&quot;http://leaflet.cloudmade.com/dist/leaflet.js&quot;&gt;&lt;/script&gt;</span>
324
+ <span class="cp"> &lt;link rel=&quot;stylesheet&quot; href=&quot;http://leaflet.cloudmade.com/dist/leaflet.css&quot;&gt;</span>
325
+ <span class="cp"> &lt;style&gt;</span>
326
+ <span class="cp"> body, html {</span>
327
+ <span class="cp"> margin: 0;</span>
328
+ <span class="cp"> padding: 0;</span>
329
+ <span class="cp"> background-color: #000000;</span>
330
+ <span class="cp"> width: 100%;</span>
331
+ <span class="cp"> height: 100%;</span>
332
+ <span class="cp"> }</span>
333
+ <span class="cp"> #map {</span>
334
+ <span class="cp"> width: 100%;</span>
335
+ <span class="cp"> height: 100%;</span>
336
+ <span class="cp"> }</span>
337
+ <span class="cp"> &lt;/style&gt;</span>
338
+ <span class="cp">&lt;/head&gt;</span>
339
+ <span class="cp">&lt;body&gt;</span>
340
+ <span class="cp"> &lt;div id=&quot;map&quot;&gt;&lt;/div&gt;</span>
341
+ <span class="cp"> &lt;script&gt;</span>
342
+ <span class="cp"> var map = new L.Map(&#39;map&#39;);</span>
343
+ <span class="cp"> var layer = new L.TileLayer(&#39;/tiles/&lt;%= params[:splat] %&gt;/{x}/{y}/{z}.png&#39;)</span>
344
+ <span class="cp"> map.addLayer(layer).setView(new L.LatLng(38, -95), 1);</span>
345
+ <span class="cp"> &lt;/script&gt;</span>
346
+ <span class="cp">&lt;/body&gt;</span>
347
+ <span class="cp">&lt;/html&gt;</span>
348
+ </pre></div>
349
+
350
+
351
+ <p>
352
+ <strong>That's in no way a safe or secure thing to put on the internet</strong>, but it will
353
+ do as a simple replacement for QGIS!
354
+ </p>
355
+
356
+ <h2>Tips and Tricks</h2>
357
+
358
+ <p>
359
+ Deploying dynamically generated maps is difficult because of the data sizes and
360
+ processing required to render them. At ProPublica we have been following
361
+ these best practices:
362
+ </p>
363
+
364
+ <ol>
365
+ <li>
366
+ If you are using a PostGIS backend make sure to limit your queries to
367
+ the bounds of the image. You will want to add a <tt>where</tt> clause to each
368
+ trip to the database like so:
369
+ <div class="highlight"><pre><span class="n">layer</span><span class="o">.</span><span class="n">query</span> <span class="no">Shape</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="s2">&quot;the_geom &amp;&amp; SRID=4326;</span><span class="si">#{</span><span class="n">map</span><span class="o">.</span><span class="n">buffered_bounds</span><span class="o">.</span><span class="n">reproject</span><span class="p">(</span><span class="n">map</span><span class="o">.</span><span class="n">srs</span><span class="p">,</span> <span class="s1">&#39;epsg:4326&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">to_wkt</span><span class="si">}</span><span class="s2">&#39;}&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">to_sql</span> <span class="k">do</span> <span class="o">|</span><span class="n">query</span><span class="o">|</span>
370
+ <span class="c1"># ...</span>
371
+ <span class="k">end</span>
372
+ </pre></div>
373
+
374
+ This will protect against doing a full table scan in your database.
375
+ </li>
376
+ <li>
377
+ <p>
378
+ If you are serving images as part of a tiled map, you'll also want to
379
+ put a proxy in front of your server with far future expiration date. At
380
+ ProPublica we're using cloudfront to serve this tile:
381
+ </p>
382
+
383
+ <img src="http://tiles-a.propublica.org/redistricting-maps/tiles/CA/12/330/789/11.png">
384
+ <p>
385
+ It will also speed up browser-side rendering if you have multiple domains
386
+ that proxy the tiles (eg. tiles-a.propublica.org, tiles-b.propublica.org, etc.)
387
+ </p>
388
+ </li>
389
+ <li>
390
+ Because of the extra time spent in collision detection for labels, you'll
391
+ probably want to limit the amount of labels you are displaying on a particular
392
+ tile.
393
+ </li>
394
+ <li>
395
+ If you are displaying labels (cf.
396
+ <a href="http://propublica.github.com/simple-tiles/#styles">text-field and font styles</a>)
397
+ you'll want to use a buffer -- usually a quarter to a half of a tile
398
+ (i.e. for a 256 tile set the buffer to be 64 to 128 pixels) -- so that
399
+ the layout isn't clipped at tile boundaries. You can assign a buffer on
400
+ <tt>SimplerTiles::Map</tt> objects like so:
401
+
402
+ <div class="highlight"><pre> <span class="n">map</span><span class="o">.</span><span class="n">buffer</span> <span class="mi">128</span>
403
+ </pre></div>
404
+
405
+ </li>
406
+ <li>
407
+ Finally, for truly speedy maps, storing your spatial data in the Web Mercator
408
+ projection -- <tt>epsg:3785</tt> -- will cut down on response time
409
+ because each geometry object won't need to be pre-processed.
410
+ </li>
411
+ </ol>
412
+
413
+ <h2>License</h2>
414
+
415
+ <pre>
416
+ Copyright (c) 2012, ProPublica
417
+
418
+ Permission is hereby granted, free of charge, to any person obtaining a copy
419
+ of this software and associated documentation files (the "Software"), to deal
420
+ in the Software without restriction, including without limitation the rights
421
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
422
+ copies of the Software, and to permit persons to whom the Software is furnished
423
+ to do so, subject to the following conditions:
424
+
425
+ The above copyright notice and this permission notice shall be included in all
426
+ copies or substantial portions of the Software.
427
+
428
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
429
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
430
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
431
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
432
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
433
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
434
+ IN THE SOFTWARE.
435
+ </pre>
436
+
437
+ <p><em>Simpler Tiles is a project of ProPublica.</em></p>
438
+ </body>
439
+ </html>
@@ -0,0 +1,19 @@
1
+ module SimplerTiles
2
+ # Each Bounds represents a rectangular box, for {Map} objects they define
3
+ # the boundary of the data to return from each {Layer}.
4
+ class Bounds
5
+ include SimplerTiles::PP
6
+
7
+ # Initialize a bounds from max and min coordinates
8
+ def initialize(maxx, maxy, minx, miny)
9
+ grow maxx, maxy
10
+ grow minx, miny
11
+ end
12
+
13
+ private
14
+
15
+ def inspect_attributes
16
+ [:to_wkt]
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ module SimplerTiles
2
+ # The Layer object contains connection info for a particular datasource and
3
+ # tracks a list of {Query}s.
4
+ class Layer
5
+ include SimplerTiles::PP
6
+
7
+ # Initialize a Layer
8
+ def initialize(source)
9
+ self.source = source
10
+ yield self if block_given?
11
+ end
12
+
13
+ # Add a query to this Layer's c list.
14
+ def query(sql, &blk)
15
+ layer = SimplerTiles::Query.new(sql, &blk)
16
+ add_query layer
17
+ end
18
+
19
+ private
20
+
21
+ def inspect_attributes
22
+ [:source]
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,55 @@
1
+ module SimplerTiles
2
+ # The Map object is the root of the style declaration for SimplerTiles.
3
+ # It wraps the methods in Simple Tiles and tracks projection, width, height
4
+ # and contains a list of Layer objects.
5
+ class Map
6
+ include SimplerTiles::PP
7
+
8
+ # Initialize a map with Mercator Projection and a tile square by default
9
+ def initialize
10
+ self.srs = "epsg:3785"
11
+ self.width = 256
12
+ self.height = 256
13
+ yield self if block_given?
14
+ end
15
+
16
+ # Add a layer to the c list of layers and yield the new layer.
17
+ def layer(source, &blk)
18
+ layer = SimplerTiles::Layer.new(source, &blk)
19
+ add_layer layer
20
+ end
21
+
22
+ # A convienence method to use Active Record configuration and add a new
23
+ # layer.
24
+ def ar_layer
25
+ if !defined?(ActiveRecord)
26
+ raise "ActiveRecord not available"
27
+ end
28
+
29
+ config = ActiveRecord::Base.connection.instance_variable_get("@config")
30
+ params = {
31
+ :dbname => config[:database],
32
+ :user => config[:username],
33
+ :host => config[:host],
34
+ :port => config[:port],
35
+ :password => config[:password]
36
+ }
37
+
38
+ layer "PG:#{params.map {|k,v| "#{k}='#{v}' "}}"
39
+ end
40
+
41
+ # Render the data to a blob of png data.
42
+ def to_png
43
+ data = ""
44
+ to_png_stream Proc.new { |chunk| data += chunk }
45
+ yield data if block_given?
46
+ data
47
+ end
48
+
49
+ private
50
+
51
+ def inspect_attributes
52
+ [:srs, :width, :height]
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,13 @@
1
+ module SimplerTiles
2
+ # PP contains a pretty print routine for SimplerTiles objects.
3
+ module PP
4
+ # A simple Nokogiri inspired inspection routine.
5
+ def inspect
6
+ attributes = inspect_attributes.map do |attribute|
7
+ "#{attribute.to_s}=#{send(attribute).inspect}"
8
+ end.join ' '
9
+
10
+ "#<#{self.class.name}:#{sprintf("0x%x", object_id)} #{attributes}>"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ module SimplerTiles
2
+ # A Query represents an OGR SQL query against a layer's datasource. Queries
3
+ # contain styles that are applied to each returned object from the datastore.
4
+ class Query
5
+ include SimplerTiles::PP
6
+
7
+ # Initialize a query with a string containing OGR SQL.
8
+ def initialize(query)
9
+ self.query = query
10
+ yield self if block_given?
11
+ end
12
+
13
+ # Styles will take a hash of style declarations and adds them to the internal
14
+ # c list.
15
+ def styles(styles)
16
+ styles.each do |k,v|
17
+ style = SimplerTiles::Style.new k, v
18
+ add_style style
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def inspect_attributes
25
+ [:query]
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,19 @@
1
+ module SimplerTiles
2
+ # Each style defines a particular directive for styling the map. For a list
3
+ # of keys and arguments refer to the simple-tiles documentation.
4
+ class Style
5
+ include SimplerTiles::PP
6
+
7
+ # Construct a new style
8
+ def initialize(key, arg)
9
+ self.key = key
10
+ self.arg = arg
11
+ end
12
+
13
+ private
14
+
15
+ def inspect_attributes
16
+ [:key, :arg]
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,4 @@
1
+ module SimplerTiles
2
+ # The version of the library
3
+ VERSION = "0.0.1"
4
+ end
@@ -0,0 +1,13 @@
1
+ # SimplerTiles contains all of the classes we'll want to define.
2
+ module SimplerTiles
3
+ # The location of this file will define the root path for SimplerTiles
4
+ ROOT = File.expand_path File.dirname(__FILE__)
5
+ end
6
+
7
+ require "#{SimplerTiles::ROOT}/simpler_tiles/simpler_tiles"
8
+ require "#{SimplerTiles::ROOT}/simpler_tiles/mixins/pp"
9
+ require "#{SimplerTiles::ROOT}/simpler_tiles/map"
10
+ require "#{SimplerTiles::ROOT}/simpler_tiles/layer"
11
+ require "#{SimplerTiles::ROOT}/simpler_tiles/query"
12
+ require "#{SimplerTiles::ROOT}/simpler_tiles/style"
13
+ require "#{SimplerTiles::ROOT}/simpler_tiles/bounds"
Binary file