Building a Map Drilldown System

In this chapter, you have already learned how to create drilldown effects for map shapes and data points. At this point you should be able to make any shape or data point drilldown to another web page with relative ease. However, it may not yet be clear how you should go about creating a multiple level map drilldown system.

You may, for example, be wondering if you'll have to create a separate web page and/or appearance file for every map to which you wish to drilldown (which would be a very tedious task if, for instance, you wanted to be able to drilldown to every zip code in the United States).

Thankfully, PopChart+OptiMap provides a number of shortcuts. Through the use of dynamic objects, macros, and PCXML, you can create a multi-level, complex map drilldown system with just one web page and one appearance file.

About this Tutorial

In this section, we will show you how to build a basic drilldown system. Our goal will be to build a system that drills-down from the United States map to a county map for each state. Although this tutorial is limited to a two-level, US state-based implementation, the strategies and skills applied will aid in the creation of any map drilldown system, no matter how big the scope.

To keep things simple, we will not connect to any data (although at the end we will briefly discuss the implications of connecting to data). Also, we will provide example code in this tutorial for ASP only. However, with minor syntax changes you should be able to follow along in any PopChart+OptiMap-supported web scripting language.

This example assumes that you are running your web server, your PopChart+OptiMap server, and PopChart+OptiMap Builder on the same machine. If this is not the case, you will need to make adjustments accordingly (like uploading your PCXML file and/or ASP to the appropriate server and changing the server address in your ASP).

For your convenience the example appearance file produced in this tutorial is located at chart_root/examples/maps/drilldownUS.pcxml. The ASP produced in this example can be found at chart_root/examples/code/ASP/drilldownUS.asp. Translations of this web page into the other Corda-supported web application environments can be found under the respective directory for each environment in the chart_root/examples directory.

Note: Note the addition of a drilldown variable in the translations. This variable can be eliminated if the proper drilldown destination has been set in the appearance file in step 15.

Prerequisites

Before starting this tutorial, you should make sure you can publish a basic map to your web application server, as described in Chapter 3, "Using Corda Embedder."

You will also need to download and install the U.S. Counties map package from the Corda Technologies website (http://www.corda.com/download/maps/). These maps are free for licensed PopChart+OptiMap users.

Finally, you may want to read up on dynamic objects (see "Dynamic Objects") and drilldown (refer to the beginning of this chapter). We will try to explain these concepts throughout the tutorial, but it will help to already be familiar with them.

Tutorial

In this tutorial, we will create a two-level map drilldown system for U.S. states using one appearance file and one web page. This tutorial will take approximately 30 minutes.

To create a basic map drilldown system

  1. Start PopChart+OptiMap Builder and create a new appearance file.
  2. Add a dynamic object.
  3. You can add a dynamic object by clicking on the Dynamic Object button on the toolbar, or by selecting Edit > Create Dynamic Object. This object is a placeholder object. We can replace it dynamically with a map using PCScript or PCXML.



  4. Add other objects as needed.
  5. You can add any other objects that you want, including text boxes and shapes. Note that to add a legend, you should make sure you have selected the dynamic object.

    Also, you may want to resize the dynamic object. The size of the maps you eventually publish will be the same size as the dynamic object in the appearance file.

  6. Test the appearance file using Preview With PCScript.
  7. This step is mostly just to illustrate how the dynamic object works. Click on the PCScript tab at the bottom left corner of PopChart+OptiMap Builder. Then enter the following PCScript into the main window:

    dynamic1.setPCXMLAttributes(FileName='maps\NorthAmerica\US\US.pcxml' ComponentName='US')

    This PCScript tells PopChart+OptiMap the location (maps\NorthAmerica\US\US.pcxml, relative to the chart_root directory) and name (US) of the map that should replace your dynamic object.

    After you have entered this PCScript, click on the Preview with PCScript button in the bottom right corner of PopChart+OptiMap Builder. You should see a map of the United States.



    Note: Don't worry if you don't see your legend. The legend will not appear until after you have specified data.

  8. Save your appearance file (File > Save).
  9. You can use any name to save the appearance file. We have chosen drilldownUS.pcxml.

  10. Save the ASP Sample Code for your appearance file to your web server.
  11. You can do this by clicking on the Sample Code tab in the bottom left corner of PopChart+OptiMap Builder. Then select ASP (COM Embedder) from the Sample Code For pull-down menu (if you are using a different scripting technology, you should instead select the appropriate web page for your environment). Make any necessary changes to the server address and image type, then click on the Save Code to File. Enter your file name, and save it to your web server (e.g. to C:\InetPub\wwwroot).

  12. Open the page you just saved in a text editor, such as Notepad.
  13. Insert PCXML into the page to load a map over your dynamic object.
  14. This can be done in two statements. First of all, define a variable to hold the PCXML string that you will send to PopChart+OptiMap. In the example below, we have defined this string as mapsource. You should add this line of code immediately before you declare the CordaEmbedder object (i.e. before the line that begins set myImage...).

    mapsource = "<DynamicObject Name='dynamic1' FileName='maps\NorthAmerica\US\US.pcxml' ComponentName='US'/>"

    Like our PCScript in step 4, the PCXML string above specifies the location and name of the map we want to insert into our dynamic object. Also note that it contains the object name of the dynamic object that we are replacing (dynamic1). For more about object names, see "What is My Object Named?".

    Now, we can send this string to PopChart+OptiMap server using the addPCXML(String) command, as shown in the preceding line of code. You should insert this line somewhere before calling getEmbeddingHTML(). For example, you could insert it after the line that begins myImage.imageType.

    myImage.addPCXML mapsource

    Important: Make sure that your ASP page does not contain any PCScript definitions. The pcScript variable should be set to an empty string (""). Otherwise, it may interfere with our example.

  15. Save your ASP, and test it to make sure it loads the map of the United States.
  16. For example, if you saved your ASP to C:\Inetpub\wwwroot\drilldownUS.asp, you could test your ASP by browsing to http://localhost/drilldownUS.asp.

  17. Get your ASP ready for dynamically loading maps by defining variables to represent the map location and map name.
  18. These definitions should occur before the map source PCXML definition in step 8. For example, you could call the map location variable maplocation. It should be set to a default value of maps/NorthAmerica/US/, since this is the base directory for all of the maps used in this tutorial.

    maplocation = "maps/NorthAmerica/US/"

    Likewise, you could call the map name variable mapname. It should be set to US, since this is the top level map in this tutorial.

    mapname = "US"

  19. Rewrite the map source PCXML string to make use of the map location and name variables.
  20. For the FileName attribute, you will need to combine the map location and map name, followed by .pcxml. For the ComponentName attribute, just use the map name. The line below shows how we would modify the mapsource variable from step 8, using maplocation and mapname from step 10.

    mapsource = "<DynamicObject Name='dynamic1' FileName='" & maplocation & mapname & ".pcxml' ComponentName='" & mapname & "'/>"

    Once you have made these changes, you may want to save your ASP and test it again to make sure there are no error messages.

  21. Insert an if-then clause that will override the map name and location based on information from the web page's query string.
  22. The query string is a string of text that can be passed to the web page from a submission form, a link, or in our case, a drilldown command. Our query string will contain two pieces of information: the nameclass, which tells us the current level of the drilldown system (e.g. State); and the map, which tells us which map to show. We will create this query string in later steps, but for now we will worry about retrieving this information in our web page.

    We can retrieve these pieces of information from the query string using the Request.QuerySting() method. For example, Request.QueryString("nameclass") will return the nameclass (our current drilldown level).

    Note: In other scripting languages, the methods for retrieving query string parameters can vary greatly. Please consult the documentation for your scripting language for more information.

    For our drilldown system, there will be two levels of maps. The top level is the default level (the U.S. map), so we don't need to worry about an if-then clause for it. However, our second level is the State level. Therefore, we will need to create an if-then clause that checks to see if nameclass is State, and makes appropriate changes to the map name and location.

    The following four lines of code show you what should be contained in this if-then clause. You should place these lines of code after your default map name and map location definitions, but before your map source definition.

    If (Request.QueryString("nameclass") = "State") Then

    mapname = Request.QueryString("map")

    maplocation = maplocation & "Counties/"

    End If

    In the first line of code, we simply check the query string for the value of nameclass. If nameclass does not exist, or is not equal to State, the remaining lines will be ignored. In the second line, we reassign our map name to the value of the map parameter in our query string. In the third line, we reassign our map location to the directory that contains the state maps we want to display, which in this case is the Counties folder inside of our base map directory (i.e. maps/NorthAmerica/US/Counties/). The last line closes the if-then clause.

    Just to make sure you're all caught up, here is the complete code for the ASP we have been building:

    Example 8.1 ASP Code for a Map Drilldown System

    <html>

    <head>

    <title>ASP Example</title>

    </head>

    <body>

    <h1>Your image will appear below</h1>

    <!-- Begin Embedder Code -->

    <%

       Dim pcScript

       Dim mapname, maplocation, mapsource

       maplocation = "maps\NorthAmerica\US\"

       mapname = "US"

       If (Request.QueryString("nameclass") = "State") Then

          maplocation = maplocation & "Counties\"

          mapname = Request.QueryString("map")

       End If

       mapsource = "<DynamicObject Name='dynamic1' FileName='" & maplocation & mapname & ".pcxml' ComponentName='" & mapname & "'/>"

       set myImage = Server.CreateObject("Corda.Embedder")

       myImage.externalServerAddress = "http://localhost:2001"

       myImage.internalCommPortAddress = "http://localhost:2002"

       myImage.appearanceFile = "examples/maps/drilldownUS.pcxml"

       myImage.userAgent = Request.ServerVariables("HTTP_USER_AGENT")

       myImage.width = 540

       myImage.height = 330

       myImage.returnDescriptiveLink = true

       myImage.language = "EN"

       myImage.pcScript = pcScript

       myImage.imageType = "FLASH"

       myImage.addPCXML mapsource

    %>

    <%= myImage.getEmbeddingHTML%>

    <!-- End Embedder Code -->

    </body>

    </html>

  23. Save your ASP, and test it by requesting a state map
  24. To request a state map, we simply request the same web page we requested in step 9, except we add a query string at the end of the request. The query string begins with a question mark (?). Then we list the first parameter (the nameclass) and set it equal to State (make sure you capitalize state). After that, we enter an ampersand (&), followed by our second parameter (map), which should be assigned to a two digit state abbreviation (such as CA).

    So, for example, if we were requesting a map of Texas, we would enter the following address in our web browser.

    http://localhost/drilldown.asp?nameclass=State&map=TX



  25. Return to the appearance file in PopChart+OptiMap Builder, and access the dynamic object's Properties dialog.
  26. This can be done by double-clicking on the dynamic object, or by selecting Edit > Properties.

  27. In the Extra PCXML box, enter your global drilldown effect.
  28. To do this, we need to enter a <DefaultShapeSettings> PCXML element. This element should contain a <Drilldown> tag, with a URL attribute set to the map's global drilldown string.

    The global drilldown string is the most important part of the equation. It tells each map shape (such as Texas or California) the web page it should drilldown to. Our goal should be to create a drilldown string that produces the same address as the one we entered in step 13. However, we want this string to be universal, so that we don't have to enter it for each state. We can make this string universal if we substitute the %_NAMECLASS and %_NAME for the name class and map name.

    The line of PCXML below shows exactly what you should enter in the Extra PCXML box, assuming your web page is called drilldownUS.asp.

    <DefaultBackgroundShapeSettings><Drilldown URL='drilldownUS.asp?nameclass=%_NAMECLASS&map=%_NAME'/></DefaultBackgroundShapeSettings>

    Note that the macros in the URL string will be replaced with real values in our map on a state-by-state basis, producing drilldown destinations like the address we used in step 13.

  29. Save your appearance file.
  30. Reload your main web page (the address you entered in step 9). When you click on any state, you should link to a detailed map of that state.
  31. Congratulations. You have successfully created a two-level map drilldown system.

Why this Worked: Conceptual Review

At this point, it is important to make several observations about why this strategy worked.

First of all, with the exception of top level maps (e.g. the world), every PopChart+OptiMap map file is named after the map object it contains. This is why we can specify the map file in step 11 by combining the map location with the map name. So, for example, the Texas map is named TX.pcxml because its main map object is called TX.

Secondly, PopChart+OptiMap map files are organized in such a manner that all of the maps on a certain level will always be contained in the same directory. Thus, in step 12, we can set the map location for any state map to maps/NorthAmerica/US/Counties/, since all the county-based state maps are in that folder.

Thirdly, you probably already realize that the dynamic object in our appearance file can be translated into any map object on the fly. However, defining the Extra PCXML in step 15 may still be somewhat of a mystery. Each dynamic object can store a number of PCXML elements inside of it. This PCXML means nothing to the dynamic object. However, when the dynamic object is transformed into a map, this extra PCXML overrides the default PCXML in the map. Thus, we are able to specify a global drilldown effect in our dynamic object by overriding the default drilldown effects in the map template. We could further extend this strategy to define default ranges for our map system, or create global data labels (see "Using a Dynamic Object as a Style Sheet").

The final pieces of the puzzle are the %_NAME and %_NAMECLASS macros, which we used in step 15. Each shape and/or data point in a map contains a number of attributes that are used to identify it. Two of those attributes are Name and NameClass, which can be retrieved in drilldown and PopUp effects using the afore-mentioned macros.

Name, of course, represents the name of the map shape or data point. In most cases, this name is exactly the same as a map object (and therefore map file) containing a more detailed view of the specified map shape or data point. For example, the US map contains 50 map shapes, each of which is named after the two-digit abbreviation for the state it represents (e.g. the Texas shape is named TX which corresponds to the TX map file named TX.pcxml). Using the %_NAME macro, we can retrieve the name of any state shape in the US map, which gives us the ability to "know" the drilldown destination of any state just by using one drilldown string.

NameClass, meanwhile, helps to define the current level of a map drilldown system. As we have already seen, one of these levels is State. Other potential values for NameClass include Country, County, City, Zip, and so on. Usually, all of the maps for a particular name class can be found in the same folder.

To find out the name or name class of a map shape or data point

  1. Open your map in PopChart+OptiMap Builder.
  2. Select the shape or data point for which you wish to learn the code or long name.
  3. Select Properties > Override Background Shape Properties.
  4. The name and name class will appear in this dialog. You should also see other internal properties, such as the item's code, parent, and long name.

Adding Multiple Levels

You can add another drilldown level to your map system simply by adding another if-then clause. The clause would look very similar to the code we used in step 12 of the tutorial, only you would be checking for a different name class, and you would need to adjust the map location directory accordingly.

For example, you've probably already noticed that the counties in our state map are drilldown-enabled (this is because our global drilldown string in step 15 applies to all maps, not just the U.S. map). However, when you click on the county, the map returns to the top level. This is because we haven't created an if-then clause to handle maps with a County name class.

If we wanted each county to drilldown to an outline map for that county, we could simply add the following if-then clause:

If (Request.QueryString("nameclass") = "County") Then

maplocation = maplocation & "Counties_Individual/"

mapname = Request.QueryString("map")

End If

Coincidentally, if you wanted to get rid of drilldown on the second level (so that the counties don't drilldown at all), you could create a drilldown variable that you would pass as an argument to a myImage.addPCXML call (right after myImage.addPCXML mapsource). When you reach the bottom level of your system, you could set this variable to disable drilldown. Otherwise, you could leave it blank. The following PCXML disables drilldown:

<Map Name='dynamic1'><DefaultBackgroundShapeSettings> <Drilldown URL=''/></DefaultBackgroundShapeSettings></Map>

Connecting to Data

At this point, the only thing left to do is connect to data. Unfortunately, we don't have a sample database to connect this example to. However, we can at least review the strategy for connecting to data.

Strategy

Let's look back to step 12 of the tutorial. In this step, we retrieved several parameters from the query string. These parameters told us which map we needed to load. But we could also use these parameters to learn what query we need to perform on our database.

Let's say, for example, that the following query gave us our data for the state of Texas:

SELECT County,sum(Sales-Expenditures) FROM Revenue WHERE Date between #7/1/2003# and #7/31/2003# AND State = 'TX' GROUP BY County

We could make this query dynamic using the map name variable. Thus, in our if-then clause for the State name class, we could assign a variable named query to the following value.

query = "SELECT County,sum(Sales-Expenditures) FROM Revenue WHERE Date between #7/1/2003# and #7/31/2003# AND State = '" & mapname & "' GROUP BY County"

We could then send this query to PopChart+OptiMap later in our code using the Corda Embedder setMapDBQuery method, as in following statement:

myImage.setMapDBQuery mapname, "areas", "", "Revenue", "", "", query

Accessing Secondary Information for Map Items

What if the information passed in the query string is not enough to determine the correct query? For example, what if you are on the county level, but in order to make the query you also need to know what state you are in. Or what if your database uses complete state names instead of two-digit abbreviations. Or what if you need to know the FIPS code for a state or a city?

Fortunately, each map item has a number of extra properties that define secondary information for that item. We introduced two of these properties LongName and Code in "Map Shape / Data Point Names". These properties increase the flexibility of PopChart+OptiMap's data import by allowing us to reference data in tables and result sets using FIPS codes or a long names instead of PopChart+OptiMap's default names.

But we can also use these properties in drilldown statements to pass information from level to level. We can access these properties through the %_LONGNAME and %_CODE macros in drilldown effects (as well as in PopUp text and labels). These macros work just like the %_NAME and %_NAMECLASS macros we used in step 15.

For example, if we needed to know complete state names (as opposed to abbreviations) for our query statement, we could pass the LongName property as another parameter in our drilldown statement:

<DefaultBackgroundShapeSettings><Drilldown URL='drilldownUS.asp?nameclass=%_NAMECLASS&map=%_NAME&longname=%_LONGNAME'/></DefaultBackgroundShapeSettings>

Then, we could access the state name by looking up the longname parameter in our query string, just as we looked up the map and nameclass parameters in step 12.

For a complete list of available properties and macros, see "Drill-down Macros".

Complete Example

Example 8.2 below shows how our drilldownUS.asp example might look connected to sample data.

Example 8.2 Map Drilldown System with Data Connectivity

<html>

<head>

<title>ASP Example</title>

</head>

<body>

<h1>Your image will appear below</h1>

<!-- Begin Embedder Code -->

<%

   Dim pcScript

   Dim mapname, maplocation, mapsource, drilldown, query

   maplocation = "maps\NorthAmerica\US\"

   mapname = "US"

   drilldown = ""

   query = "SELECT State,sum(Sales-Expenditures) FROM Revenue WHERE Date between #7/1/2003# and #7/31/2003# GROUP BY State"

   If (Request.QueryString("nameclass") = "State") Then

      maplocation = maplocation & "Counties\"

      mapname = Request.QueryString("map")

      query = "SELECT County,sum(Sales-Expenditures) FROM Revenue WHERE Date between #7/1/2003# and #7/31/2003# AND State = '" & mapname & "' GROUP BY County"

   End If

   If (Request.QueryString("nameclass") = "County") Then

      maplocation = maplocation & "Counties_Individual/"

      mapname = Request.QueryString("map")

      query = "SELECT County,sum(Sales-Expenditures) FROM Revenue WHERE Date between #7/1/2003# and #7/31/2003# AND County = '" & Request.QueryString("longname") & "' GROUP BY County"

      drilldown = "<Map Name='dynamic1'><DefaultBackgroundShapeSettings><Drilldown URL=''/></DefaultBackgroundShapeSettings></Map>"

   End If

   mapsource = "<DynamicObject Name='dynamic1' FileName='" & maplocation & mapname & ".pcxml' ComponentName='" & mapname & "'/>"

   set myImage = Server.CreateObject("Corda.Embedder")

   myImage.externalServerAddress = "http://localhost:2001"

   myImage.internalCommPortAddress = "http://localhost:2002"

   myImage.appearanceFile = "examples/maps/drilldownUS.pcxml"

   myImage.userAgent = Request.ServerVariables("HTTP_USER_AGENT")

   myImage.width = 540

   myImage.height = 330

   myImage.returnDescriptiveLink = true

   myImage.language = "EN"

   myImage.pcScript = pcScript

   myImage.imageType = "FLASH"

   myImage.addPCXML mapsource

   myImage.addPCXML drilldown

   myImage.setMapDBQuery mapname, "areas", "", "Revenue", "", "", query

%>

<%= myImage.getEmbeddingHTML%>

<!-- End Embedder Code -->

</body>

</html>

In this example, note that we have to add another parameter to our query string for the long name. To accommodate this additional parameter, we had to change our Extra PCXML from step 15 as follows:

<DefaultBackgroundShapeSettings><Drilldown URL='drilldownUS.asp?nameclass=%_NAMECLASS&map=%_NAME&longname=%_LONGNAME'/></DefaultBackgroundShapeSettings>

This addition was necessary since the county data in our hypothetical database references counties by the county name instead of the FIPS code, whereas the PopChart+OptiMap map templates store counties under FIPS codes. Thus, for the county level, we need to use the FIPS code when specifying the map and file location, but we need to use the actual county name in the where clause of the query.

Fortunately, PopChart+OptiMap will accept both the county name (i.e long name) and FIPS code when importing data, meaning the tables produced by our query will import properly no matter how the counties have been indexed (see "Map Shape / Data Point Names").