Up to this point, your web maps have displayed images obtained from the server: either through pre-drawn tiles or dynamically-drawn WMS maps. An alternative approach is to send some text to the client containing the coordinates and attributes of features, then allow the client to draw the layer. This approach can improve the speed and interactivity of your web map when used wisely.
You may be asking, "How does a client like a web browser know how to draw GIS data?" Although web browsers don't "know" anything about GIS, they indeed have the ability to draw vector graphics, which is just the simple process of connecting screen coordinates with a symbol. Web mapping APIs can read a series of coordinates provided in a GeoJSON file, or a KML file, to give a few examples, and convert these into screen coordinates to be drawn by the browser.
Advantages of drawing vectors on the client
Speed and interactivity are two principal advantages of drawing vector features on the client rather than the server. Once your web browser has read the vector data from the server, users of the web map can interact with the data in a lightning fast manner. Let's suppose I have a web map of the United States with all the NFL football teams displayed on it. The basemap is coming from an OpenStreetMap tiled layer. The football teams are coming from a GeoJSON file. When the map loads, all the GeoJSON for the teams is read by my web browser. This includes all geographic coordinates and the attribute information for each team. Now I can click on any team and see its information without making another request to the server. Contrast this with the farmers markets mashup from the previous lesson, which required a WMS GetFeatureInfo query to the server (and the associated wait time) any time you clicked a market.
Let's suppose I want to highlight a map symbol whenever a user hovers over it, thereby providing a visual cue that someone can click the symbol. A web browser can change the symbol styling quickly enough that this effect works. In contrast, if a round trip to the server were required on every hover event, my app (and possibly my server) could easily grind to a standstill.
Challenges with drawing vectors on the client
Not all use cases are appropriate for drawing vectors on the client side. If you're displaying hundreds of features at a time, or some complex polygons with many vertices, you're probably better off asking the server to draw the map and send it to you. Browsers can get weighed down to a crawl if handed too many vector graphics to draw at once. Sending a lot of complex graphics also results in more network traffic, as all the coordinates must be downloaded by the client.
To keep performance crisp, it's a good idea to generalize the layers that you draw on the client as much as possible, at least at the smallest map scales. For example, when displaying the United States at the nationwide level, you should not be using a file that contains every tiny coastal island in the state of Maine. You might switch to loading a more detailed file when the user zooms in past a particular scale.
Labeling can also be a challenge with browser-drawn graphics. Although web browsers can draw text on the screen at a given coordinate, they have no label placement algorithms like the ones employed by GeoServer and TileMill. Your labels will likely overlap each other. You are better off allowing the user to discover the label through interactivity, displaying the label in a popup or HTML DIV when someone clicks a feature.
Finally, the symbol choices offered by web browsers are relatively elementary. You can always instruct the browser to draw a graphic, such as an SVG file, but you won't be able to get some of the complex lines and fills available in programs like TileMill or ArcGIS. Of course, if your client happens to be a desktop application such as QGIS, you don't have to worry as much about available symbol choices.
How to draw vectors on the client
Web mapping APIs typically provide classes for drawing vector layers with the browser; however, these go by different names with each API. For a few simple standalone vectors, you will often see a "marker" class. For more complex layers, you may see something like FeatureGroup (Leaflet) or FeatureLayer (Esri). OpenLayers has a Layer.Markers class and a Layer.Vector class for these respective purposes.
Desktop programs such as QGIS can view KML, GeoJSON, GML (described in Lesson 8), and various other text-based vector data formats.
Approaches for retrieving data from the server
When you define a vector layer, you need to specify the approach that your client will take for retrieving the data from the server. Remember that your client is not requesting map images from the server, but it does need to retrieve the coordinates of the vectors and any associated attribute information. Some popular approaches include:
- Retrieve all the data at the time the layer is loaded. In Leaflet, this is the default behavior. It requires an initial performance hit, but it makes your application responsive by ensuring that it never has to go back to the server to make another request. This approach is inappropriate for very large amounts of data.
- Retrieve only the data within the current map view. When the map view changes, make a new request. Although OpenLayers offers this approach through its "bbox" loading strategy, I am not aware of this functionality being available in Leaflet out of the box (please correct me if you know otherwise). It works well when there's too much data in the dataset to download at once, but it can make your map seem clunky if people zoom and pan very quickly. Sometimes, logic is incorporated to retain features already requested (for example, in the case of a small map pan where the new map view includes some features that were previously downloaded).
- Retrieve only some of the vector features from the dataset based on a filter or query condition. Leaflet offers a filter option when you create a GeoJSON layer. This can narrow down the data requested, allowing you to get the effect of the first approach (retrieve all data) without downloading the entire dataset.
- Retrieve vectors in uniformly sized chunks, or "vector tiles" as you learned about in Lesson 5. This is only possible if the server administrator has pregenerated a set of tiles. Various plugins are available for consuming vector tiles via Leaflet. OpenLayers versions 3 and above have a VectorTile layer class designed for this.
You may see other variations on the above approaches, including the re-loading of layers at fixed intervals to represent an ever-changing phenomenon, such as the position of a fleet of ships.