├── CODEOWENRS ├── 1.0 ├── demo.json ├── interaction.md └── utfgrid.md ├── 1.2 ├── demo.json ├── interaction.md └── utfgrid.md ├── 1.3 ├── demo.json ├── interaction.md └── utfgrid.md ├── LICENSE ├── CHANGELOG.md └── README.md /CODEOWENRS: -------------------------------------------------------------------------------- 1 | * @mapbox/maps -------------------------------------------------------------------------------- /1.0/demo.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/utfgrid-spec/HEAD/1.0/demo.json -------------------------------------------------------------------------------- /1.2/demo.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/utfgrid-spec/HEAD/1.2/demo.json -------------------------------------------------------------------------------- /1.3/demo.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/utfgrid-spec/HEAD/1.3/demo.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This work is licensed under the Creative Commons Attribution 3.0 United States License. 2 | To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/ 3 | or send a letter to 4 | 5 | Creative Commons, 6 | 444 Castro Street, Suite 900, 7 | Mountain View, 8 | California, 94041, USA. 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.3 2 | 3 | * Adjusts default resolution to 4 from 2 4 | * Improves Javascript validation example for variable-resolution grids 5 | * Rewords sections to accomodate variable-dpi tiles. 6 | 7 | ## 1.2 8 | 9 | * Deprecates the `formatter` option and adds `template`, a replacement 10 | based off of Mustache templates. 11 | * Skips 1.1 in order to start sync with [MBTiles](https://github.com/mapbox/mbtiles-spec). 12 | 13 | ## 1.0 14 | 15 | * First version of UTFGrid external to MBTiles. This is identical 16 | to UTFGrid in MBTiles 1.1. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UTFGrid 2 | 3 | UTFGrid is a specification for rasterized interaction data. As of version 1.2, 4 | it was removed from incubation in the 5 | [MBTiles Specification](https://github.com/mapbox/mbtiles-spec) and split into 6 | its own repository. 7 | 8 | See CHANGELOG.md for per-version changes. 9 | 10 | ## License 11 | 12 | This specification is licensed under a [Creative Commons Attribution 3.0 United States License](http://creativecommons.org/licenses/by/3.0/us/). 13 | 14 | Applications which make use of the specification are not subject to any restrictions. 15 | 16 | ## Implementations 17 | 18 | ### Write 19 | 20 | * Mapnik's [grid_renderer](https://github.com/mapnik/mapnik/wiki/MapnikRenderers#grid_renderer) (Uses Antigrain Geometry library for rendering). 21 | * [Various python sample implementations](https://github.com/springmeyer/utfgrid-example-writers) 22 | * GeoScript [groovy example](https://github.com/jericks/geoscript-groovy/blob/master/examples/utfgrid.groovy) 23 | * [TileStache](http://tilestache.org/) 24 | * [create-utfgrids](https://github.com/Ecotrust/create-utfgrids) 25 | 26 | ### Read 27 | 28 | * Wax for adding support to the Leaflet, Modest Maps, OpenLayers, and Google Maps clients: [examples](http://mapbox.com/wax/interaction-mm.html), [code](https://github.com/mapbox/wax/blob/master/control/lib/gridinstance.js) 29 | * [Leaflet.utfgrid](https://github.com/danzel/Leaflet.utfgrid) 30 | * OpenLayers Native: [blog post](http://www.perrygeo.net/wordpress/?p=160), [general demo](http://openlayers.org/dev/examples/utfgrid.html), [example multi-grid](http://openlayers.org/dev/examples/utfgrid_twogrids.html), [example geography-class](http://openlayers.org/dev/examples/utfgrid-geography-class.html) 31 | * [GDAL MBTiles support](http://www.gdal.org/frmt_mbtiles.html) 32 | * [Landez - Python module](https://github.com/makinacorpus/landez) 33 | 34 | ### Servers 35 | 36 | * TileMill - via [tilelive.js](https://github.com/mapbox/tilelive.js) which uses [tilelive-mapnik](https://github.com/mapbox/tilelive-mapnik) to request grid creation and [node-mbtiles](https://github.com/mapbox/node-mbtiles) to cache and fetch grids stored in [MBTiles](http://mapbox.com/mbtiles-spec/) format. 37 | * [TileStache's](https://github.com/migurski/TileStache) `TileStache.Goodies.Providers.MapnikGrid:Provider` 38 | * [django-mbtiles](https://github.com/makinacorpus/django-mbtiles) which serves grids stored in *MBTiles* along with tiles using a simple template tag. 39 | 40 | ## Authors 41 | 42 | * Tom MacWright (tmcw) 43 | * Will White (willwhite) 44 | * Konstantin Kaefer (kkaefer) 45 | * Justin Miller (incanus) 46 | * Dane Springmeyer (springmeyer) 47 | -------------------------------------------------------------------------------- /1.0/interaction.md: -------------------------------------------------------------------------------- 1 | # Interaction 2 | 3 | Tile servers can enhance tilesets with interactivity by implementing two additional HTTP endpoints. 4 | 5 | * `[base path]/layer.json`: A layer manifest JSON containing the interaction formatter function and other optional attributes. 6 | * `[base path]/{n}/{n}/{n}.grid.json`: A UTFGrid JSON file corresponding to its adjacent tile image. 7 | 8 | `[base path]` refers to the full layer URL prior to any x, y or z coordinates. 9 | 10 | Examples: 11 | 12 | TMS-style URL schema 13 | 14 | http://example.com/1.0.0/world/0/0/0.png // tile image for 0/0/0 15 | http://example.com/1.0.0/world/0/0/0.grid.json // utfgrid for 0/0/0 16 | http://example.com/1.0.0/world/layer.json // layer manifest 17 | 18 | OSM-style URL schema 19 | 20 | http://example.com/0/0/0.png // tile image for 0/0/0 21 | http://example.com/0/0/0.grid.json // utfgrid for 0/0/0 22 | http://example.com/layer.json // layer manifest 23 | 24 | ## layer.json 25 | 26 | The layer manifest should provide a JSON object with the following keys: 27 | 28 | * `formatter`: String. Anonymous javascript function for formatting feature data from UTFGrid JSON. **Required**. 29 | * `legend`: String. Self-contained HTML that may be displayed as a legend for this layer. **Optional**. 30 | 31 | Example response from `layer.json`: 32 | 33 | { 34 | "formatter": "function(options, data) { return data.NAME; }", 35 | "legend": "Countries of the World" 36 | } 37 | 38 | Each `layer.json` item should be represented by a single row in the `metadata` table where `key,value` match its key and value in the `layer.json` object. 39 | 40 | ### formatter 41 | 42 | The UTFGrid specification puts no constraints on the properties and type of data stored in values, only that the data is valid JSON. Formatter functions are used to provide application-specific representations of the data. 43 | 44 | Only a single formatter is permitted per tileset. The formatter function can be used for different presentations (hover, click, etc), by passing an `options` object as the first parameter to the function. The second parameter must be the JSON object from the dataset, in the form of an object. 45 | 46 | function (options, data) { 47 | ... 48 | return formatted_output; 49 | } 50 | 51 | The `options` argument has one standardized property, `format`, which is expected to be a string, and all formatters must support two values, "teaser" and "full". 52 | 53 | function (options, data) { 54 | if (options.format == 'teaser') { 55 | return '

' + data.NAME + '

'; 56 | } else if (options.format == 'full') { 57 | return '

' + data.NAME + '

' + data.AREA; 58 | } 59 | } 60 | 61 | ### legend 62 | 63 | A tileset may provide an HTML string that can be rendered by the client as a legend. The string should be self-contained and not reference external stylesheets, scripts or images. The [Data URI scheme](http://en.wikipedia.org/wiki/Data_URI_scheme) may be used to embed images or other data if necessary. 64 | 65 |
+10% population
66 |
+5% population
67 |
+0% population
68 |
-5% population
69 | 70 | ## grid.json 71 | 72 | See `utfgrid.md` for the format and storage of UTFGrid JSON. 73 | 74 | -------------------------------------------------------------------------------- /1.2/interaction.md: -------------------------------------------------------------------------------- 1 | # Interaction 2 | 3 | Tile servers can enhance tilesets with interactivity by implementing two additional HTTP endpoints. 4 | 5 | * `[base path]/layer.json`: A layer manifest JSON containing the interaction formatter function and other optional attributes. 6 | * `[base path]/{n}/{n}/{n}.grid.json`: A UTFGrid JSON file corresponding to its adjacent tile image. 7 | 8 | `[base path]` refers to the full layer URL prior to any x, y or z coordinates. 9 | 10 | Examples: 11 | 12 | OSM-style URL schema 13 | 14 | http://example.com/0/0/0.png // tile image for 0/0/0 15 | http://example.com/0/0/0.grid.json // utfgrid for 0/0/0 16 | http://example.com/layer.json // layer manifest 17 | 18 | ## TileJSON 19 | 20 | UTFGrid requires additions to the [TileJSON](https://github.com/mapbox/tilejson-spec) 21 | payload for a layer: 22 | 23 | * `template`: String. In the format of a mustache template. 24 | * `legend`: String. Self-contained HTML that may be displayed as a legend for 25 | this layer. **Optional**. 26 | 27 | Example response from `layer.json`: 28 | 29 | { 30 | "template": "{{NAME}}", 31 | "legend": "Countries of the World" 32 | } 33 | 34 | Each `layer.json` item should be represented by a single row in the `metadata` table where `key,value` match its key and value in the `layer.json` object. 35 | 36 | ### Template 37 | 38 | As of UTFGrid 1.1, the `formatter` key is deprecated and replaced by `template`. 39 | Template is to be a [mustache](http://mustache.github.com/) format string that 40 | produces 41 | HTML, which will be cleaned with an HTML whitelist after generation. 42 | 43 | #### Mustache 44 | 45 | Template data is specified according to the 46 | [mustache specification](http://mustache.github.com/mustache.5.html). 47 | The full specification is supported, but no partials are provided, 48 | or should be provided by implementations. 49 | 50 | Given the switch to templates from formatters, the `options` object 51 | is no longer available. Its functionality is emulated by setting 52 | 'format flags' on each data object. 53 | 54 | For an example data object like 55 | 56 | 57 | { 58 | "id": "helloworld" 59 | } 60 | 61 | 62 | This will be transformed into 63 | 64 | 65 | { 66 | "id": "helloworld" 67 | "__location__": true 68 | } 69 | 70 | 71 | By the tooltip/interaction implementation, in order to trigger 72 | the `location` template. Note that `true`, `1`, and all non-false 73 | values are equal to template, so implementations may set 74 | `"__location__": 1` to save bytes. 75 | 76 | The template implementation could be: 77 | 78 | 79 | {{#__location__}} 80 | http://your.com/{{id}} 81 | {{/__location__}} 82 | {{#__full__}} 83 | This content has the id {{id}} 84 | {{/__full__}} 85 | {{#__teaser__}} 86 | {{id}} 87 | {{/__teaser__}} 88 | 89 | 90 | Which, for this implementation, will produce the output 91 | 92 | 93 | http://your.com/helloworld 94 | 95 | 96 | ### legend 97 | 98 | A tileset may provide an HTML string that can be rendered by the client as a legend. The string should be self-contained and not reference external stylesheets, scripts or images. The [Data URI scheme](http://en.wikipedia.org/wiki/Data_URI_scheme) may be used to embed images or other data if necessary. 99 | 100 |
+10% population
101 |
+5% population
102 |
+0% population
103 |
-5% population
104 | 105 | ## grid.json 106 | 107 | See `utfgrid.md` for the format and storage of UTFGrid JSON. 108 | 109 | -------------------------------------------------------------------------------- /1.3/interaction.md: -------------------------------------------------------------------------------- 1 | # Interaction 2 | 3 | Tile servers can enhance tilesets with interactivity by implementing two additional HTTP endpoints. 4 | 5 | * `[base path]/layer.json`: A layer manifest JSON containing the interaction formatter function and other optional attributes. 6 | * `[base path]/{n}/{n}/{n}.grid.json`: A UTFGrid JSON file corresponding to its adjacent tile image. 7 | 8 | `[base path]` refers to the full layer URL prior to any x, y or z coordinates. 9 | 10 | Examples: 11 | 12 | OSM-style URL schema 13 | 14 | http://example.com/0/0/0.png // tile image for 0/0/0 15 | http://example.com/0/0/0.grid.json // utfgrid for 0/0/0 16 | http://example.com/layer.json // layer manifest 17 | 18 | ## TileJSON 19 | 20 | UTFGrid requires additions to the [TileJSON](https://github.com/mapbox/tilejson-spec) 21 | payload for a layer: 22 | 23 | * `template`: String. In the format of a mustache template. 24 | * `legend`: String. Self-contained HTML that may be displayed as a legend for 25 | this layer. **Optional**. 26 | 27 | Example response from `layer.json`: 28 | 29 | { 30 | "template": "{{NAME}}", 31 | "legend": "Countries of the World" 32 | } 33 | 34 | Each `layer.json` item should be represented by a single row in the `metadata` table where `key,value` match its key and value in the `layer.json` object. 35 | 36 | ### Template 37 | 38 | As of UTFGrid 1.1, the `formatter` key is deprecated and replaced by `template`. 39 | Template is to be a [mustache](http://mustache.github.com/) format string that 40 | produces 41 | HTML, which will be cleaned with an HTML whitelist after generation. 42 | 43 | #### Mustache 44 | 45 | Template data is specified according to the 46 | [mustache specification](http://mustache.github.com/mustache.5.html). 47 | The full specification is supported, but no partials are provided, 48 | or should be provided by implementations. 49 | 50 | Given the switch to templates from formatters, the `options` object 51 | is no longer available. Its functionality is emulated by setting 52 | 'format flags' on each data object. 53 | 54 | For an example data object like 55 | 56 | 57 | { 58 | "id": "helloworld" 59 | } 60 | 61 | 62 | This will be transformed into 63 | 64 | 65 | { 66 | "id": "helloworld" 67 | "__location__": true 68 | } 69 | 70 | 71 | By the tooltip/interaction implementation, in order to trigger 72 | the `location` template. Note that `true`, `1`, and all non-false 73 | values are equal to template, so implementations may set 74 | `"__location__": 1` to save bytes. 75 | 76 | The template implementation could be: 77 | 78 | 79 | {{#__location__}} 80 | http://your.com/{{id}} 81 | {{/__location__}} 82 | {{#__full__}} 83 | This content has the id {{id}} 84 | {{/__full__}} 85 | {{#__teaser__}} 86 | {{id}} 87 | {{/__teaser__}} 88 | 89 | 90 | Which, for this implementation, will produce the output 91 | 92 | 93 | http://your.com/helloworld 94 | 95 | 96 | ### legend 97 | 98 | A tileset may provide an HTML string that can be rendered by the client as a legend. The string should be self-contained and not reference external stylesheets, scripts or images. The [Data URI scheme](http://en.wikipedia.org/wiki/Data_URI_scheme) may be used to embed images or other data if necessary. 99 | 100 |
+10% population
101 |
+5% population
102 |
+0% population
103 |
-5% population
104 | 105 | ## grid.json 106 | 107 | See `utfgrid.md` for the format and storage of UTFGrid JSON. 108 | 109 | -------------------------------------------------------------------------------- /1.3/utfgrid.md: -------------------------------------------------------------------------------- 1 | # UTFGrid 2 | 3 | The UTFGrid encoding scheme encodes interactivity data for a tile in a space 4 | efficient manner. It is designed to be used in browsers, e.g. for displaying 5 | tooltips when hovering over certain features of a map tile. 6 | 7 | Since slower browsers and machines can't cope with rendering the actual 8 | polygons used to draw vectors on the map tile, we use a grid-based approach 9 | where we store the associated information for each pixel. 10 | 11 | UTFGrid uses [JSON](http://en.wikipedia.org/wiki/JSON) as a container format. 12 | It is exclusively geared towards square tiles. 13 | 14 | ## Grid 15 | 16 | To achieve reasonable speed in browsers, we store information for a pixel in 17 | long strings, where each character's Unicode code point is the key for retrieving 18 | the information associated with that pixel. When we have less than 96 unique 19 | IDs, this means that the space taken up by storing each pixel separately is 20 | 256 * 256 = 64 KB. Gzipping the grid data typically reduces it to a size below 2K. 21 | 22 | By default, UTFGrid operates on a 4x4 grid, meaning that a tile at zoom level 23 | 0 that contains the entire world in its extent will have an grid resolution 24 | of 64x64. We take advantage of UTF-8's variable length codepoint encoding: 25 | all ASCII characters are encoded as is, that means that the first 94 codepoints 26 | are encoded with their code number as a single byte (codes `0x20`, `0x21`, 27 | `0x23`-`0x5B` and `0x5D`-`0x7F`). 28 | IDs with a number larger than that will get encoded as multiple bytes. 29 | 30 | ## Encoding IDs 31 | 32 | [JSON](http://www.ietf.org/rfc/rfc4627) doesn't allow control characters, `"` 33 | and `\` to be encoded as their literal UTF-8 representation. **Encoding** an 34 | ID works as follows: 35 | 36 | * Add 3210. 37 | * If the result is >= 3410, add 1. 38 | * If the result is >= 9210, add 1. 39 | 40 | This ensures that all characters that cannot be represented natively are skipped. 41 | 42 | **Decoding** works as follows: 43 | 44 | * If the codepoint is >= 9310, subtract 1. 45 | * If the codepoint is >= 3510, subtract 1. 46 | * Subtract 3210. 47 | 48 | ## Mapping an ID to a key 49 | 50 | The UTFgrid file contains an array in a property named `grid` at the root level. 51 | Each entry represents a row in the grid. Each array entry is a string that 52 | contains the UTF-8 encoded codepoint for each column. The string length 53 | corresponds to the number of entries in the `grid` array. Only powers of two are allowed. 54 | 55 | The keys are stored in an array named `keys` at the root level. The index of 56 | each key represents the ID that it is associated to. 57 | 58 | Retrieving a key from a coordinate works as follows (`json` is the root level 59 | object, `x` and `y` are the coordinates, starting from top left at 0, and 60 | `size` is the number of entries in the `grid` key): 61 | 62 | * `var factor = 256 / size, row = y / factor, col = x / factor` 63 | * `var id = json.grid[row].charCodeAt(col);` is the character that contains the encoded ID. 64 | * Decode the id as described in *"Encoding IDs"*. 65 | * `var key = json.keys[id];` retrieves the ID associated with the coordinate. 66 | 67 | All divisions are integer divisions. 68 | 69 | ## Mapping a key to data 70 | 71 | The JSON file may contain an optional `data` property at the root level. 72 | If it isn't present, the client looks up the obtained key in its internal data 73 | store. If the lookup key is not present, it queries the server with the 74 | missing keys. If the `data` property is present, but the key cannot be found, 75 | the client must behave as if there were no `data` property. 76 | 77 | An empty key signifies the unavailability of information for that pixel. 78 | No action may be taken to retrieve data for an empty (`""`) key. 79 | 80 | 81 | ## Example UTFGrid JSON file 82 | 83 | ```json 84 | { "grid": 85 | [ " !!!#########", 86 | " !!!#########", 87 | " !!!!#########", 88 | " !!!##########", 89 | " !! !!!##########", 90 | " !!!#########", 91 | " !!######### ", 92 | " ! !!! ####### ", 93 | " ### ", 94 | " $ ", 95 | " $$ %%", 96 | " $$$$$$$%%", 97 | " $$$$$$$%%", 98 | " $$$$$$$$$%%", 99 | " $$$$$$$$$$%%", 100 | " $$$$$$$$$$$$%", 101 | " $$$$$$$$$%%%%", 102 | " $$$$$$$$$%%%%%", 103 | " $$$$$$$$%%%%%%", 104 | " $$$$$$$%%%%%%%", 105 | " $$$$%%%%%%%%%%", 106 | " $$$$%%%%%%%%%%%", 107 | " # # # $$$$$%%%%%%%%%%%%", 108 | " $$$$$$$%%%%%%%%%%%%", 109 | " $$$&&&&'%%%%%%%%%%%", 110 | " $$$$&&&&'''%%%%%%%%%", 111 | " $$$$'''''''''%%%%%%%%", 112 | " $$$$'''''''''''%%%%%%", 113 | " $$$$&''''''''((((%%%%%", 114 | " $$$&&''''''''(((((%%%%", 115 | " $$$&&'''''''''(((((((%%", 116 | " $$$&&''''''''''(((((((%", 117 | " $$$&&&''''''''''((((((((", 118 | " ''''''''''''''''((((((((", 119 | " '''''''''''''''((((((((", 120 | " '''''''''''''''((((((((", 121 | " '''''''''''''''((((((((", 122 | " '''''''''''''''((((((((", 123 | " '''''''''''''''((((((((", 124 | " ) '''''''''''''''((((((((", 125 | " ***'''''''''''''(((((((", 126 | " *****'''''''''''(((((((", 127 | " )) ******'''(((((((((((((((", 128 | " *******(((((((((((((((++", 129 | " *******(((((((((((((++++", 130 | " ********((((((((((((++++", 131 | " ***,,-**((((((((((++++++", 132 | " ,,,,-------(((((+++++++", 133 | " ,,---------(((((+++++.+", 134 | " --------(((((+++....", 135 | " -///----0000000....", 136 | " ////----0000000....", 137 | " /////1---0000000...", 138 | " ///11--0000000....", 139 | " 111110000000....", 140 | " 11110000000....", 141 | " 1111000000....", 142 | " 1100 . ", 143 | " ", 144 | " ", 145 | " ", 146 | " ", 147 | " ", 148 | " " ], 149 | "keys": 150 | [ "", 151 | "1", 152 | "2", 153 | "3", 154 | "4", 155 | "5", 156 | "6", 157 | "7", 158 | "8", 159 | "9", 160 | "10", 161 | "11", 162 | "12", 163 | "13", 164 | "14", 165 | "15", 166 | "16" ], 167 | "data": 168 | { "1": { "admin": "Portugal" }, 169 | "2": { "admin": "Spain" }, 170 | "3": { "admin": "Morocco" }, 171 | "4": { "admin": "Algeria" }, 172 | "5": { "admin": "Western Sahara" }, 173 | "6": { "admin": "Mauritania" }, 174 | "7": { "admin": "Mali" }, 175 | "8": { "admin": "Cape Verde" }, 176 | "9": { "admin": "Senegal" }, 177 | "10": { "admin": "Burkina Faso" }, 178 | "11": { "admin": "Guinea Bissau" }, 179 | "12": { "admin": "Guinea" }, 180 | "13": { "admin": "Ghana" }, 181 | "14": { "admin": "Sierra Leone" }, 182 | "15": { "admin": "Ivory Coast" }, 183 | "16": { "admin": "Liberia" } } } 184 | ``` 185 | 186 | To test implementations, [`demo.json`](https://github.com/mapbox/mbtiles-spec/blob/master/1.1/demo.json) contains a grid that consists of 65501 different keys. This is the maximum possible in this version of UTFGrid. Implementors should check that obtaining a coordinate should return the key `y * 256 + x` for all x/y, with the exception of y = 255 and x >= 222 and x <= 255 returning 65501 due to the maximum codepoint allowed in JSON. 187 | 188 | A dummy code validation routine is given here: 189 | 190 | ```javascript 191 | var json = JSON.parse(/* demo.json */); 192 | 193 | // the resolution of the grid. adjust this for your grid. 194 | var resolution = 4; 195 | 196 | var key = 0, 197 | dimension = 256 / resolution; 198 | 199 | for (var y = 0; y < dimension; y++) { 200 | for (var x = 0; x < dimension; x++) { 201 | var code = json.grid[y].charCodeAt(x); 202 | if (code >= 93) code--; 203 | if (code >= 35) code--; 204 | code -= 32; 205 | 206 | assert(code == key); 207 | 208 | if (key < 65501) key++; 209 | } 210 | } 211 | ``` 212 | -------------------------------------------------------------------------------- /1.0/utfgrid.md: -------------------------------------------------------------------------------- 1 | # UTFGrid 2 | 3 | The UTFGrid encoding scheme encodes interactivity data for a tile in a space efficient manner. It is designed to be used in browsers, e.g. for displaying tooltips when hovering over certain features of a map tile. 4 | 5 | Since slower browsers and machines can't cope with rendering the actual polygons used to draw vectors on the map tile, we use a grid-based approach where we store the associated information for each pixel. 6 | 7 | UTFGrid uses JSON as a container format. It is exclusively geared towards square 256x256 pixel tiles. 8 | 9 | ## Grid 10 | 11 | To achieve reasonable speed in browsers, we store information for a pixel in long strings, where each character's Unicode code point is the key for retrieving the information associated with that pixel. When we have less than 96 unique IDs, this means that the space taken up by storing each pixel separately is 256 * 256 = 64 KB. Gzipping the grid data typically reduces it to a size below 2K. 12 | 13 | By default, UTFGrid operates on a 2x2 grid. This means that the maximum information resolution for a 256x256 tile is 128x128. If each pixel had different information, we require a 14 bit wide ID (2^14 = 16384). However, most tiles won't have that many IDs; they'll typically have a couple of dozens IDs. Therefore, we take advantage of UTF-8's variable length codepoint encoding: all ASCII characters are encoded as is, that means that the first 94 codepoints are encoded with their code number as a single byte (codes `0x20`, `0x21`, `0x23`-`0x5B` and `0x5D`-`0x7F`). IDs with a number larger than that will get encoded as multiple bytes. 14 | 15 | ## Encoding IDs 16 | 17 | [JSON](http://www.ietf.org/rfc/rfc4627) doesn't allow control characters, `"` and `\` to be encoded as their literal UTF-8 representation. **Encoding** an ID works as follows: 18 | 19 | * Add 3210. 20 | * If the result is >= 3410, add 1. 21 | * If the result is >= 9210, add 1. 22 | 23 | This ensures that all characters that cannot be represented natively are skipped. 24 | 25 | **Decoding** works as follows: 26 | 27 | * If the codepoint is >= 9310, subtract 1. 28 | * If the codepoint is >= 3510, subtract 1. 29 | * Subtract 3210. 30 | 31 | ## Mapping an ID to a key 32 | 33 | The UTFgrid file contains an array in a property named `grid` at the root level. Each entry represents a row in the grid. Each array entry is a string that contains the UTF-8 encoded codepoint for each column. The string length corresponds to the number of entries in the `grid` array. Only powers of two are allowed. 34 | 35 | The keys are stored in an array named `keys` at the root level. The index of each key represents the ID that it is associated to. 36 | 37 | Retrieving a key from a coordinate works as follows (`json` is the root level object, `x` and `y` are the coordinates, starting from top left at 0, and `size` is the number of entries in the `grid` key): 38 | 39 | * `var factor = 256 / size, row = y / factor, col = x / factor` 40 | * `var id = json.grid[row].charCodeAt(col);` is the character that contains the encoded ID. 41 | * Decode the id as described in *"Encoding IDs"*. 42 | * `var key = json.keys[id];` retrieves the ID associated with the coordinate. 43 | 44 | All divisions are integer divisions. 45 | 46 | ## Mapping a key to data 47 | 48 | The JSON file may contain an optional `data` property at the root level. If it isn't present, the client looks up the obtained key in its internal data store. If the lookup key is not present, it queries the server with the missing keys. If the `data` property is present, but the key cannot be found, the client must behave as if there were no `data` property. 49 | 50 | An empty key signifies the unavailability of information for that pixel. No action may be taken to retrieve data for an empty (`""`) key. 51 | 52 | 53 | ## Example UTFGrid JSON file 54 | 55 | { "grid": 56 | [ 57 | " !!!!!!!########################$$$$$$$$$$$$$$$$%%%%%%%%%% %%%%%%%%%%%%%%%% % %", 58 | " !!!!!!########################$$$$$$$$$$$$$$$$$%%%%%%%%%%% %%%%%%%%%%%%% %%%% %%", 59 | " !!!!!########################$$$$$$$$$$$$$$$$$%%%%%%%%%%%%% %%%%%%% %%%%%% %%", 60 | " !!!!!###########################$$$$$$$$$$$$$$$$$%%%%%%%%%%%%% %%% %%%%%%%%%%", 61 | " !!!!###########################$$$$$$$$$$$$$$$$$%%%%%%%%%%%%% %%%%%%%%%%%%", 62 | " !!!!!!###################### ###$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%%%%%%%%%", 63 | " ! !!!!!###################### $$$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%%%%%%%%%%%", 64 | " !!!!!!!##################### $$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%%%%%%%%%%%%", 65 | " !!!!!!!#################### $$$$$$$$$$$$%%%%%%%%%%%%% %%%%%%%%%%%%%%", 66 | " !!!!!##################### $$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%%%%%%%%%%%", 67 | " ! !!!!!##################### $$$$$$$$$$$$%%%%%%%%%%%%%% % %%% %%%%%%%%%%%%%", 68 | " ! !!!!!!!##################### $$$$$$$$$$$$$%%%%%%%%%%%%%%% %%%% %%%%%%%%%%%%%", 69 | " !!!!!!##################### $$$$$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%% % %%%%%%%%%%%%", 70 | " !!!!!!###################### $$$$$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%%%% %%%%%%%%%%%%%", 71 | " ! !!!!!!!!##################### $$$$$$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%", 72 | " !!!!!!!!!!!#################### $$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%", 73 | " !!!!!!!!!!!!################### $$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%", 74 | " !!! !!!!####################### $$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%", 75 | " !!!! !!!######################## $$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%", 76 | " ! !! !!!!####################### $$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 77 | " !!!! ! !!!###################### $$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 78 | " ! ! !!!!!!!!#################### $$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 79 | " !!!!!!!!!!!!#################### $ $$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 80 | " !!!!!!!!!!!!!################## $$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 81 | " !!!! !!!!!!!!!!################## $$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 82 | " !!!! !!!!!!!!!!################# $$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 83 | " !!! !!!!!!!!!!!!!################# $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 84 | " !!!!!!!!!!!!!!!!!############### $$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 85 | " !!!!!!!!!!!!!!!!!!!############### $$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 86 | " !!!!!!!!!!!!!!!!!!!!############### $$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 87 | " !!!!!!!!!!!!!!!!!!!!############### $$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 88 | " !!!!!!!!!!!!!!!!!!!!############### $$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 89 | " !!!!!!!!!!!!!!!!!!!!!############# $$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 90 | " !!!!!!!!!!!!!!!!!!!!!!############ $$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 91 | " !!!!!!!!!!!!!!!!!!!!!!############ $$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 92 | " ! ! !!!!!!!!!!!!!!!!!!############ $$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 93 | " !!!!!!!!!!!!!!!!!!!!############## $$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 94 | " !!!!!!!!!!!!!!!!!!!!!############## $$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 95 | " !!!!!!!!!!!!!!!!!!!!!################ $ $$$$$$$$$$$$$ $$$% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 96 | " !!!! !!!!!!!!!!!!!!!!################ $ $$$$$$$$$$$$ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 97 | " !!!!!!!!!!!!!!!!!!!!################# & & $ $$$$$$ $ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 98 | " ! !!!!!!!!!!!!!!!!!!################## & $ $$$$ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 99 | " ! !!!!!!!!!!!!!!!!!##################### $ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 100 | " !!!!!!!!!!!!! !!!#################### %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 101 | " !!! !!!!!!!!!!! !!!############## ##### ''' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 102 | " ! !!!!!!!!!!!! !!!################### ''''''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 103 | " !!!!!!!!!!!! !!!################### '''''''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 104 | " !!!!!!!!!!!! #!################## '''''''''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 105 | " !!!!!!!!!!! ################## '' ''''''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 106 | " !!!!!!!!!! ################ '''''''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 107 | " !!!!!!!! ################ '''' '''''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 108 | " !!!!!! ############### '' '''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 109 | " !!!! ############## ' ''(''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 110 | " ############# # ((((''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 111 | " ) ############## # ( (((((''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 112 | " ) ############## ## ((( (((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 113 | " )) ############ ## (((( ((((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 114 | " )))) ############ # (((((( (((((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 115 | " ) ))) ########### # # ((((((((((((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 116 | " )) ))) ########### ((((((((((((((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 117 | " )))))) ########### ((((((((((((((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 118 | " )))))))) ######### # (((****((((*(((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 119 | " ))))))) ########## (************((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 120 | " ))))))) )) #### **************(((((+++%+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 121 | " ))))) ) ))) #### ***************((+++++++%++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 122 | " )))) ) )))) #### ***************++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 123 | " )))) )) )))) # ***************++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 124 | " ))) )) ) ) %**************+++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 125 | " )))) ) ) %%%%**********++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 126 | " ,,,, ))) -- %%%%%%%%*********++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 127 | " ,,, ) , ----- %%%%%%%*********+++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 128 | " ,,,,,, ,,,, ------- ----%%%%%%-*******+++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 129 | " ,,,,,, ,,,,,, -----------------------*****+*++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 130 | " , ,,,,, ,,,,,,,, -------------------------***+++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 131 | ". ,,,,,,,,,,,,,,, --------------------------+++++++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 132 | " ,,,,,,,,,,,,,,,,,,,,---------------------------+++++++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 133 | ". /// ,,,,,,,,,,,,,,,,,,,,---------------------------+++++++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 134 | ". /////,,,,,,,,,,,,,,,,,,,,---------------------------++++++++++++++++++++++%+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 135 | ". .. /////,,,,,,,,,,,,,,,,,,,,----------------------------+++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 136 | "..... ///////,,,,,,,,,,,,,,,,,,,,,---------------------------+++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 137 | "..... //////,,,,,,,,,,,,,,,,,,,,,,-------------------------+++++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 138 | "..... ////////,,,,,,,,,,,,,,,,,,,,,------------------------+++++++++++++++++++++++++%%0000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 139 | "..... ////////,,,,,,,,,,,,,,,,,,,,,,--------------------------++++++++++++++++++++000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 140 | ".... //////,,,,,,,,,,,,,,,,,,,,,,,,--------------------------++000000++++++++++++0000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 141 | "... //////,,,,,,,,,,,,,,,,,,,,,,,,-------------------------+0000000000+++++0+++00000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 142 | ".. ///11///,,,,,,,,,,,,,,,,,,,,,,,,,-------------------------0000000000000000000+0000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 143 | "..... 111111111/,,,,,,,,,,,,,,,,,,,,,,,,,-------------------------0000000000000000000000000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 144 | "... 22111111111/,,,,,,,,,,,,,,,,,,,,,,,3,3-------------------------00000000000000000000000000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%", 145 | " 2222211111111,,,,,,,,,,,,,,,,,,,,,,33333------------------------00000000000000000000000000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%", 146 | " 2222221111111,,,,,,,,,,,,,,,,,,,,333333333----------------------00000000000000000000000000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%", 147 | " 2222222111111,,,,,,,,,,,,,,,,,,33333333333--3------------------000000000000000000000000000000000000%00%%%%%%%%%%%%%%%%%%%%%", 148 | " 22222222111114,,,,,,,,,,,,,,,,,3333333333333333----------------00000000000000000000000000000000000000000%0%%%%%%%%%%%%%%%%%%", 149 | " 22222222222211144,,,,,,,,,,,,,,,,,33333333333333333-------------000000000000000000000000000000000000000000000%%%%%%%%%%%%%%%%%", 150 | " 222222222222222144,,,,,,,,,,,,,,,,,333333333333333333-----------000000000000000000000000000000000000000000000000%0%%%%%%%%%%%%%", 151 | " 222222222222222222,,,,,,,,,,,,,,,,,,33333333333333335555-55555--00000000000000000000000000000000000000000000000000%%%%%%%%%%%%%", 152 | "2222222222222222222222,,,,,,,,,,,,,,,,33333333333333555555555555-0000000000000000000000000000000000000000000000000%%%%%%%%%%%%%%", 153 | "222222222222222222222222,,,,,,,,,,,,,,,333366333333555555555555500000000000000000000000000000000000000000000000000%%%%%%%%%%%%%%", 154 | "22222222222222222222222,,,,,,,,,,,,,,,,,3366666665555555555555550000000000000000000000000000000000000000000000000%%%%%%%%%%%%%%%", 155 | "22222222222222222222222,,,,,,,,,,,,,,,,666666666555555555557775500000000000000000000000000000000000000000000000000%%%%%%%%%%%%%%", 156 | "2222222222222222222222,,,,,,,,,,,,,,,66666666666655555557577777770000000000089990000000000000000000000000000000000%%%%%%%%%%%%%%", 157 | "2222222222222222222222,,,,,,,,,,,,,,,66666666666675555777777777777880000000888999990000000000000000000000000000000%%%%%%%%%%%%%%", 158 | "2222222222222222222222,,,,,,,,,,,,,,,66666666666677757777777777788888880888888999999000000000000000000000000000%%%%%%%%%%%%%%%%%", 159 | "2222222222222222222222::::::6,66,6666,66666666667777777777777778888888888888888999900000000000000000000000000%%%%%%%%%%%%%%%%%%%", 160 | "22222222222222222222::::::::6,6666666666666666677777777777777778888888888888888999999000000000000000000000000%%%%%%%%%%%%%%%%%%%", 161 | "22222222222222222222::::::::6666666666666666666777777777777777888888888888888888999990000000000000000000000 %%%%%%%%%%%%%%%%", 162 | "2222222222222222222:::::::::::;6;;;;6666666666<7777777777777778888888888888888888999990000000000000000000 %%%%%%%%%%%%%%%%%%", 163 | "222222222222222222:::::::::::;;;;;;;;;;6666<<<<77777777777777888888888888888888889999900 0000000000 %%%%%%%%%%%%%%%%%%%%", 164 | "22222222222222222222::::;::;;;;;;;;;;;;<<<<<<<===777777777777888888888888888888889900000 000000000 %%%%%%%%%%%%%%%%%%%", 165 | "22222222222222222222:::;;;;;;;;;;;;;;;;<<<<<<=====777777>>88888888888888888888889990000 00 00 %%%%%%%%%%%%%%%%%%%", 166 | "22222222222222222222;;;;;;;;;;;;;;;;;;;<<<<<<======77=>>>>>888888888888888888888890000 000 %%%%%%%%%%%%%%%%%%%%", 167 | "22222222222222222222;;;;;;;;;;;;;;;;; <<<<==========>>>>>>8888888888888888888899000 000000 %%%%%%%%%%%%%%%%%%%%%", 168 | "222222222222222222222;;;;;;;;;;;;;; ================>>>>>8888888888888888888880088 000000 000% %%%%%%%%%%%%%%%%%%%%", 169 | "2222222222222222222;;;;;;;;;;;;;;;;; == ==?=????=?==>>>>>>>88888888888888888888888 00000 00 %%%%%%%%%%%%%%%%%%%%%%%", 170 | "22222222222222222222;;;;;;;;;;;;;;; = ==???????????>>>>>888888888888888888888888 0000 %%%%%%%%%%%%%%%%%%%%%", 171 | "22222222222222222222;;;;;;;;;;;;;;; = ===?????????>>>>>>>>8>88888888888888888 000 %%%%%%%%%%%%%%%%%%%", 172 | "22222222222222222222;;;;; ;;;;;;;;; ====????????>>>>>>>>>>88888888888888888 %%%%%%%%%%%%%%%%%%", 173 | "2222222222222222222222;; ;;;;;;;; ===?????????>>>>>>>>>@88888888888@8888 %%%%%%%%%%%%%%%%", 174 | "2222222222222222222222; ;;;;;;;; ===????????>>>>>>>>@@88888888@@@@@@88 %%%%%%%%%%%%%%%", 175 | "222222222222222222222 ;;;;;;;;; ===???????>>>>>>>>@@@@@@@@@@@@@@@@@@ %%%%%%%%%%%%%%", 176 | "22222222222 222 ;;;;;;;;;; = =?????A>>>>>>>>>@@@@@@@@@@@@@@@ BBB%%%%%%%%%%", 177 | "222222222 ;;;;;;;;;; = =???AAA>>>>>>>>>@@@@@@@@@@@@@@ BBBBBB%%%%%", 178 | "22C222222 ;;;;;;;;; ??AAAAA>>>>>>@@@@@@@@@@@@@@@@ BBBBBBBB%%%", 179 | "CCCCC2222 222 ;;;;;;;;; =AAADD>>>>>>@@@@@@@@@@@@@@@ BBBBBBBBB", 180 | "CCCCCCCCCC 222 ;;;;;;;; AADDD>>>>E@@@@@@@@@@@@@@@ BBBBBBBBB", 181 | "CCCCCCCCCC 22 ;;;;;;;;; ADDD>EEEEE@@@@@@@@@@@@F@@ BBBBBBBBB", 182 | "CCCCCCCCC 22 ;;;;;;;;;;;; DDDEEEEEEE@@@@@@@@@FFFFF FFFFFFFF BBBBBBBBB", 183 | "CCCCCCC 2 ;;;;;;;;;; DDDEEEEEEE@@@G@@@@@GFFFFF FFFFFFFFFFFF BBBFBBBBB", 184 | "CCCCCC ;;;;;;; DDDEEEEEEGGGGGGGGGGFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFBBBBB" 185 | ], 186 | "keys": [ "", "578", "752", "246", "643", "248", "233", "428", "208", "440", "112", "276", "616", "826", "528", "804", "56", "250", 187 | "203", "442", "703", "40", "348", "642", "498", "756", "380", "705", "191", "688", "70", "100", "499", "268", "724", "8", 188 | "807", "792", "300" ], 189 | "data": { 190 | "8": "Albania", 191 | "40": "Austria", 192 | "56": "Belgium", 193 | "70": "Bosnia and Herzegovina", 194 | "100": "Bulgaria", 195 | "112": "Belarus", 196 | "191": "Croatia", 197 | "203": "Czech Republic", 198 | "208": "Denmark", 199 | "233": "Estonia", 200 | "246": "Finland", 201 | "250": "France", 202 | "268": "Georgia", 203 | "276": "Germany", 204 | "300": "Greece", 205 | "348": "Hungary", 206 | "380": "Italy", 207 | "428": "Latvia", 208 | "440": "Lithuania", 209 | "442": "Luxembourg", 210 | "498": "Republic of Moldova", 211 | "499": "Montenegro", 212 | "528": "Netherlands", 213 | "578": "Norway", 214 | "616": "Poland", 215 | "642": "Romania", 216 | "643": "Russia", 217 | "688": "Serbia", 218 | "703": "Slovakia", 219 | "705": "Slovenia", 220 | "724": "Spain", 221 | "752": "Sweden", 222 | "756": "Switzerland", 223 | "792": "Turkey", 224 | "804": "Ukraine", 225 | "807": "The former Yugoslav Republic of Macedonia", 226 | "826": "United Kingdom" 227 | } 228 | } 229 | 230 | When minified and gzipped, the resulting file is 2071 bytes with the key to data mapping and 1645 bytes without. 231 | 232 | To test implementations, [`demo.json`](https://github.com/mapbox/mbtiles-spec/blob/master/1.1/demo.json) contains a grid that consists of 65501 different keys. This is the maximum possible in this version of UTFGrid. Implementors should check that obtaining a a coordinate should return the key `y * 256 + x` for all x/y, with the exception of y = 255 and x >= 222 and x <= 255 returning 65501 due to the maximum codepoint allowed in JSON. 233 | 234 | A dummy code validation routine is given here: 235 | 236 | ```javascript 237 | json = JSON.parse(/* demo.json */); 238 | var key = 0; 239 | for (var y = 0; y < 256; y++) { 240 | for (var x = 0; x < 256; x++) { 241 | var code = json.grid[y].charCodeAt(x); 242 | if (code >= 93) code--; 243 | if (code >= 35) code--; 244 | code -= 32; 245 | 246 | assert(code == key); 247 | 248 | if (key < 65501) key++; 249 | } 250 | } 251 | ``` 252 | -------------------------------------------------------------------------------- /1.2/utfgrid.md: -------------------------------------------------------------------------------- 1 | # UTFGrid 2 | 3 | The UTFGrid encoding scheme encodes interactivity data for a tile in a space efficient manner. It is designed to be used in browsers, e.g. for displaying tooltips when hovering over certain features of a map tile. 4 | 5 | Since slower browsers and machines can't cope with rendering the actual polygons used to draw vectors on the map tile, we use a grid-based approach where we store the associated information for each pixel. 6 | 7 | UTFGrid uses JSON as a container format. It is exclusively geared towards square 256x256 pixel tiles. 8 | 9 | ## Grid 10 | 11 | To achieve reasonable speed in browsers, we store information for a pixel in long strings, where each character's Unicode code point is the key for retrieving the information associated with that pixel. When we have less than 96 unique IDs, this means that the space taken up by storing each pixel separately is 256 * 256 = 64 KB. Gzipping the grid data typically reduces it to a size below 2K. 12 | 13 | By default, UTFGrid operates on a 2x2 grid. This means that the maximum information resolution for a 256x256 tile is 128x128. If each pixel had different information, we require a 14 bit wide ID (2^14 = 16384). However, most tiles won't have that many IDs; they'll typically have a couple of dozens IDs. Therefore, we take advantage of UTF-8's variable length codepoint encoding: all ASCII characters are encoded as is, that means that the first 94 codepoints are encoded with their code number as a single byte (codes `0x20`, `0x21`, `0x23`-`0x5B` and `0x5D`-`0x7F`). IDs with a number larger than that will get encoded as multiple bytes. 14 | 15 | ## Encoding IDs 16 | 17 | [JSON](http://www.ietf.org/rfc/rfc4627) doesn't allow control characters, `"` and `\` to be encoded as their literal UTF-8 representation. **Encoding** an ID works as follows: 18 | 19 | * Add 3210. 20 | * If the result is >= 3410, add 1. 21 | * If the result is >= 9210, add 1. 22 | 23 | This ensures that all characters that cannot be represented natively are skipped. 24 | 25 | **Decoding** works as follows: 26 | 27 | * If the codepoint is >= 9310, subtract 1. 28 | * If the codepoint is >= 3510, subtract 1. 29 | * Subtract 3210. 30 | 31 | ## Mapping an ID to a key 32 | 33 | The UTFgrid file contains an array in a property named `grid` at the root level. Each entry represents a row in the grid. Each array entry is a string that contains the UTF-8 encoded codepoint for each column. The string length corresponds to the number of entries in the `grid` array. Only powers of two are allowed. 34 | 35 | The keys are stored in an array named `keys` at the root level. The index of each key represents the ID that it is associated to. 36 | 37 | Retrieving a key from a coordinate works as follows (`json` is the root level object, `x` and `y` are the coordinates, starting from top left at 0, and `size` is the number of entries in the `grid` key): 38 | 39 | * `var factor = 256 / size, row = y / factor, col = x / factor` 40 | * `var id = json.grid[row].charCodeAt(col);` is the character that contains the encoded ID. 41 | * Decode the id as described in *"Encoding IDs"*. 42 | * `var key = json.keys[id];` retrieves the ID associated with the coordinate. 43 | 44 | All divisions are integer divisions. 45 | 46 | ## Mapping a key to data 47 | 48 | The JSON file may contain an optional `data` property at the root level. If it isn't present, the client looks up the obtained key in its internal data store. If the lookup key is not present, it queries the server with the missing keys. If the `data` property is present, but the key cannot be found, the client must behave as if there were no `data` property. 49 | 50 | An empty key signifies the unavailability of information for that pixel. No action may be taken to retrieve data for an empty (`""`) key. 51 | 52 | 53 | ## Example UTFGrid JSON file 54 | 55 | { "grid": 56 | [ 57 | " !!!!!!!########################$$$$$$$$$$$$$$$$%%%%%%%%%% %%%%%%%%%%%%%%%% % %", 58 | " !!!!!!########################$$$$$$$$$$$$$$$$$%%%%%%%%%%% %%%%%%%%%%%%% %%%% %%", 59 | " !!!!!########################$$$$$$$$$$$$$$$$$%%%%%%%%%%%%% %%%%%%% %%%%%% %%", 60 | " !!!!!###########################$$$$$$$$$$$$$$$$$%%%%%%%%%%%%% %%% %%%%%%%%%%", 61 | " !!!!###########################$$$$$$$$$$$$$$$$$%%%%%%%%%%%%% %%%%%%%%%%%%", 62 | " !!!!!!###################### ###$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%%%%%%%%%", 63 | " ! !!!!!###################### $$$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%%%%%%%%%%%", 64 | " !!!!!!!##################### $$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%%%%%%%%%%%%", 65 | " !!!!!!!#################### $$$$$$$$$$$$%%%%%%%%%%%%% %%%%%%%%%%%%%%", 66 | " !!!!!##################### $$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%%%%%%%%%%%", 67 | " ! !!!!!##################### $$$$$$$$$$$$%%%%%%%%%%%%%% % %%% %%%%%%%%%%%%%", 68 | " ! !!!!!!!##################### $$$$$$$$$$$$$%%%%%%%%%%%%%%% %%%% %%%%%%%%%%%%%", 69 | " !!!!!!##################### $$$$$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%% % %%%%%%%%%%%%", 70 | " !!!!!!###################### $$$$$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%%%% %%%%%%%%%%%%%", 71 | " ! !!!!!!!!##################### $$$$$$$$$$$$$$$$$%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%", 72 | " !!!!!!!!!!!#################### $$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%", 73 | " !!!!!!!!!!!!################### $$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%", 74 | " !!! !!!!####################### $$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%", 75 | " !!!! !!!######################## $$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%", 76 | " ! !! !!!!####################### $$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 77 | " !!!! ! !!!###################### $$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 78 | " ! ! !!!!!!!!#################### $$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 79 | " !!!!!!!!!!!!#################### $ $$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 80 | " !!!!!!!!!!!!!################## $$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 81 | " !!!! !!!!!!!!!!################## $$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 82 | " !!!! !!!!!!!!!!################# $$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 83 | " !!! !!!!!!!!!!!!!################# $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 84 | " !!!!!!!!!!!!!!!!!############### $$$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 85 | " !!!!!!!!!!!!!!!!!!!############### $$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 86 | " !!!!!!!!!!!!!!!!!!!!############### $$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 87 | " !!!!!!!!!!!!!!!!!!!!############### $$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 88 | " !!!!!!!!!!!!!!!!!!!!############### $$$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 89 | " !!!!!!!!!!!!!!!!!!!!!############# $$$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 90 | " !!!!!!!!!!!!!!!!!!!!!!############ $$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 91 | " !!!!!!!!!!!!!!!!!!!!!!############ $$$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 92 | " ! ! !!!!!!!!!!!!!!!!!!############ $$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 93 | " !!!!!!!!!!!!!!!!!!!!############## $$$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 94 | " !!!!!!!!!!!!!!!!!!!!!############## $$$$$$$$$$$$$$$$$$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 95 | " !!!!!!!!!!!!!!!!!!!!!################ $ $$$$$$$$$$$$$ $$$% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 96 | " !!!! !!!!!!!!!!!!!!!!################ $ $$$$$$$$$$$$ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 97 | " !!!!!!!!!!!!!!!!!!!!################# & & $ $$$$$$ $ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 98 | " ! !!!!!!!!!!!!!!!!!!################## & $ $$$$ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 99 | " ! !!!!!!!!!!!!!!!!!##################### $ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 100 | " !!!!!!!!!!!!! !!!#################### %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 101 | " !!! !!!!!!!!!!! !!!############## ##### ''' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 102 | " ! !!!!!!!!!!!! !!!################### ''''''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 103 | " !!!!!!!!!!!! !!!################### '''''''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 104 | " !!!!!!!!!!!! #!################## '''''''''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 105 | " !!!!!!!!!!! ################## '' ''''''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 106 | " !!!!!!!!!! ################ '''''''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 107 | " !!!!!!!! ################ '''' '''''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 108 | " !!!!!! ############### '' '''''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 109 | " !!!! ############## ' ''(''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 110 | " ############# # ((((''''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 111 | " ) ############## # ( (((((''''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 112 | " ) ############## ## ((( (((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 113 | " )) ############ ## (((( ((((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 114 | " )))) ############ # (((((( (((((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 115 | " ) ))) ########### # # ((((((((((((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 116 | " )) ))) ########### ((((((((((((((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 117 | " )))))) ########### ((((((((((((((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 118 | " )))))))) ######### # (((****((((*(((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 119 | " ))))))) ########## (************((((((((%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 120 | " ))))))) )) #### **************(((((+++%+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 121 | " ))))) ) ))) #### ***************((+++++++%++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 122 | " )))) ) )))) #### ***************++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 123 | " )))) )) )))) # ***************++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 124 | " ))) )) ) ) %**************+++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 125 | " )))) ) ) %%%%**********++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 126 | " ,,,, ))) -- %%%%%%%%*********++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 127 | " ,,, ) , ----- %%%%%%%*********+++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 128 | " ,,,,,, ,,,, ------- ----%%%%%%-*******+++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 129 | " ,,,,,, ,,,,,, -----------------------*****+*++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 130 | " , ,,,,, ,,,,,,,, -------------------------***+++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 131 | ". ,,,,,,,,,,,,,,, --------------------------+++++++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 132 | " ,,,,,,,,,,,,,,,,,,,,---------------------------+++++++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 133 | ". /// ,,,,,,,,,,,,,,,,,,,,---------------------------+++++++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 134 | ". /////,,,,,,,,,,,,,,,,,,,,---------------------------++++++++++++++++++++++%+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 135 | ". .. /////,,,,,,,,,,,,,,,,,,,,----------------------------+++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 136 | "..... ///////,,,,,,,,,,,,,,,,,,,,,---------------------------+++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 137 | "..... //////,,,,,,,,,,,,,,,,,,,,,,-------------------------+++++++++++++++++++++++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 138 | "..... ////////,,,,,,,,,,,,,,,,,,,,,------------------------+++++++++++++++++++++++++%%0000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 139 | "..... ////////,,,,,,,,,,,,,,,,,,,,,,--------------------------++++++++++++++++++++000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 140 | ".... //////,,,,,,,,,,,,,,,,,,,,,,,,--------------------------++000000++++++++++++0000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 141 | "... //////,,,,,,,,,,,,,,,,,,,,,,,,-------------------------+0000000000+++++0+++00000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 142 | ".. ///11///,,,,,,,,,,,,,,,,,,,,,,,,,-------------------------0000000000000000000+0000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 143 | "..... 111111111/,,,,,,,,,,,,,,,,,,,,,,,,,-------------------------0000000000000000000000000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", 144 | "... 22111111111/,,,,,,,,,,,,,,,,,,,,,,,3,3-------------------------00000000000000000000000000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%", 145 | " 2222211111111,,,,,,,,,,,,,,,,,,,,,,33333------------------------00000000000000000000000000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%", 146 | " 2222221111111,,,,,,,,,,,,,,,,,,,,333333333----------------------00000000000000000000000000000000%%%%%%%%%%%%%%%%%%%%%%%%%%%", 147 | " 2222222111111,,,,,,,,,,,,,,,,,,33333333333--3------------------000000000000000000000000000000000000%00%%%%%%%%%%%%%%%%%%%%%", 148 | " 22222222111114,,,,,,,,,,,,,,,,,3333333333333333----------------00000000000000000000000000000000000000000%0%%%%%%%%%%%%%%%%%%", 149 | " 22222222222211144,,,,,,,,,,,,,,,,,33333333333333333-------------000000000000000000000000000000000000000000000%%%%%%%%%%%%%%%%%", 150 | " 222222222222222144,,,,,,,,,,,,,,,,,333333333333333333-----------000000000000000000000000000000000000000000000000%0%%%%%%%%%%%%%", 151 | " 222222222222222222,,,,,,,,,,,,,,,,,,33333333333333335555-55555--00000000000000000000000000000000000000000000000000%%%%%%%%%%%%%", 152 | "2222222222222222222222,,,,,,,,,,,,,,,,33333333333333555555555555-0000000000000000000000000000000000000000000000000%%%%%%%%%%%%%%", 153 | "222222222222222222222222,,,,,,,,,,,,,,,333366333333555555555555500000000000000000000000000000000000000000000000000%%%%%%%%%%%%%%", 154 | "22222222222222222222222,,,,,,,,,,,,,,,,,3366666665555555555555550000000000000000000000000000000000000000000000000%%%%%%%%%%%%%%%", 155 | "22222222222222222222222,,,,,,,,,,,,,,,,666666666555555555557775500000000000000000000000000000000000000000000000000%%%%%%%%%%%%%%", 156 | "2222222222222222222222,,,,,,,,,,,,,,,66666666666655555557577777770000000000089990000000000000000000000000000000000%%%%%%%%%%%%%%", 157 | "2222222222222222222222,,,,,,,,,,,,,,,66666666666675555777777777777880000000888999990000000000000000000000000000000%%%%%%%%%%%%%%", 158 | "2222222222222222222222,,,,,,,,,,,,,,,66666666666677757777777777788888880888888999999000000000000000000000000000%%%%%%%%%%%%%%%%%", 159 | "2222222222222222222222::::::6,66,6666,66666666667777777777777778888888888888888999900000000000000000000000000%%%%%%%%%%%%%%%%%%%", 160 | "22222222222222222222::::::::6,6666666666666666677777777777777778888888888888888999999000000000000000000000000%%%%%%%%%%%%%%%%%%%", 161 | "22222222222222222222::::::::6666666666666666666777777777777777888888888888888888999990000000000000000000000 %%%%%%%%%%%%%%%%", 162 | "2222222222222222222:::::::::::;6;;;;6666666666<7777777777777778888888888888888888999990000000000000000000 %%%%%%%%%%%%%%%%%%", 163 | "222222222222222222:::::::::::;;;;;;;;;;6666<<<<77777777777777888888888888888888889999900 0000000000 %%%%%%%%%%%%%%%%%%%%", 164 | "22222222222222222222::::;::;;;;;;;;;;;;<<<<<<<===777777777777888888888888888888889900000 000000000 %%%%%%%%%%%%%%%%%%%", 165 | "22222222222222222222:::;;;;;;;;;;;;;;;;<<<<<<=====777777>>88888888888888888888889990000 00 00 %%%%%%%%%%%%%%%%%%%", 166 | "22222222222222222222;;;;;;;;;;;;;;;;;;;<<<<<<======77=>>>>>888888888888888888888890000 000 %%%%%%%%%%%%%%%%%%%%", 167 | "22222222222222222222;;;;;;;;;;;;;;;;; <<<<==========>>>>>>8888888888888888888899000 000000 %%%%%%%%%%%%%%%%%%%%%", 168 | "222222222222222222222;;;;;;;;;;;;;; ================>>>>>8888888888888888888880088 000000 000% %%%%%%%%%%%%%%%%%%%%", 169 | "2222222222222222222;;;;;;;;;;;;;;;;; == ==?=????=?==>>>>>>>88888888888888888888888 00000 00 %%%%%%%%%%%%%%%%%%%%%%%", 170 | "22222222222222222222;;;;;;;;;;;;;;; = ==???????????>>>>>888888888888888888888888 0000 %%%%%%%%%%%%%%%%%%%%%", 171 | "22222222222222222222;;;;;;;;;;;;;;; = ===?????????>>>>>>>>8>88888888888888888 000 %%%%%%%%%%%%%%%%%%%", 172 | "22222222222222222222;;;;; ;;;;;;;;; ====????????>>>>>>>>>>88888888888888888 %%%%%%%%%%%%%%%%%%", 173 | "2222222222222222222222;; ;;;;;;;; ===?????????>>>>>>>>>@88888888888@8888 %%%%%%%%%%%%%%%%", 174 | "2222222222222222222222; ;;;;;;;; ===????????>>>>>>>>@@88888888@@@@@@88 %%%%%%%%%%%%%%%", 175 | "222222222222222222222 ;;;;;;;;; ===???????>>>>>>>>@@@@@@@@@@@@@@@@@@ %%%%%%%%%%%%%%", 176 | "22222222222 222 ;;;;;;;;;; = =?????A>>>>>>>>>@@@@@@@@@@@@@@@ BBB%%%%%%%%%%", 177 | "222222222 ;;;;;;;;;; = =???AAA>>>>>>>>>@@@@@@@@@@@@@@ BBBBBB%%%%%", 178 | "22C222222 ;;;;;;;;; ??AAAAA>>>>>>@@@@@@@@@@@@@@@@ BBBBBBBB%%%", 179 | "CCCCC2222 222 ;;;;;;;;; =AAADD>>>>>>@@@@@@@@@@@@@@@ BBBBBBBBB", 180 | "CCCCCCCCCC 222 ;;;;;;;; AADDD>>>>E@@@@@@@@@@@@@@@ BBBBBBBBB", 181 | "CCCCCCCCCC 22 ;;;;;;;;; ADDD>EEEEE@@@@@@@@@@@@F@@ BBBBBBBBB", 182 | "CCCCCCCCC 22 ;;;;;;;;;;;; DDDEEEEEEE@@@@@@@@@FFFFF FFFFFFFF BBBBBBBBB", 183 | "CCCCCCC 2 ;;;;;;;;;; DDDEEEEEEE@@@G@@@@@GFFFFF FFFFFFFFFFFF BBBFBBBBB", 184 | "CCCCCC ;;;;;;; DDDEEEEEEGGGGGGGGGGFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFBBBBB" 185 | ], 186 | "keys": [ "", "578", "752", "246", "643", "248", "233", "428", "208", "440", "112", "276", "616", "826", "528", "804", "56", "250", 187 | "203", "442", "703", "40", "348", "642", "498", "756", "380", "705", "191", "688", "70", "100", "499", "268", "724", "8", 188 | "807", "792", "300" ], 189 | "data": { 190 | "8": "Albania", 191 | "40": "Austria", 192 | "56": "Belgium", 193 | "70": "Bosnia and Herzegovina", 194 | "100": "Bulgaria", 195 | "112": "Belarus", 196 | "191": "Croatia", 197 | "203": "Czech Republic", 198 | "208": "Denmark", 199 | "233": "Estonia", 200 | "246": "Finland", 201 | "250": "France", 202 | "268": "Georgia", 203 | "276": "Germany", 204 | "300": "Greece", 205 | "348": "Hungary", 206 | "380": "Italy", 207 | "428": "Latvia", 208 | "440": "Lithuania", 209 | "442": "Luxembourg", 210 | "498": "Republic of Moldova", 211 | "499": "Montenegro", 212 | "528": "Netherlands", 213 | "578": "Norway", 214 | "616": "Poland", 215 | "642": "Romania", 216 | "643": "Russia", 217 | "688": "Serbia", 218 | "703": "Slovakia", 219 | "705": "Slovenia", 220 | "724": "Spain", 221 | "752": "Sweden", 222 | "756": "Switzerland", 223 | "792": "Turkey", 224 | "804": "Ukraine", 225 | "807": "The former Yugoslav Republic of Macedonia", 226 | "826": "United Kingdom" 227 | } 228 | } 229 | 230 | When minified and gzipped, the resulting file is 2071 bytes with the key to data mapping and 1645 bytes without. 231 | 232 | To test implementations, [`demo.json`](https://github.com/mapbox/mbtiles-spec/blob/master/1.1/demo.json) contains a grid that consists of 65501 different keys. This is the maximum possible in this version of UTFGrid. Implementors should check that obtaining a coordinate should return the key `y * 256 + x` for all x/y, with the exception of y = 255 and x >= 222 and x <= 255 returning 65501 due to the maximum codepoint allowed in JSON. 233 | 234 | A dummy code validation routine is given here: 235 | 236 | ```javascript 237 | json = JSON.parse(/* demo.json */); 238 | var key = 0; 239 | for (var y = 0; y < 256; y++) { 240 | for (var x = 0; x < 256; x++) { 241 | var code = json.grid[y].charCodeAt(x); 242 | if (code >= 93) code--; 243 | if (code >= 35) code--; 244 | code -= 32; 245 | 246 | assert(code == key); 247 | 248 | if (key < 65501) key++; 249 | } 250 | } 251 | ``` 252 | --------------------------------------------------------------------------------