The Chameleon Language
Chameleon is the language used by GeoBase to specify how to draw a map. A Chameleon script is a plain text script and can be written in any text editor. Verizon Connect GeoBase ships with Verizon Connect GeoBase WorkBench, which is specifically designed for writing Chameleon (and Alchemy) scripts and provides many useful tools to aid script development.
Chameleon scripts are made up of a number of blocks. These blocks are arranged in a hierarchy, the top-most block is the map block. Constants are declared outside the map block and all rendering and querying statements are inside the map block. The map block may contain a number of other blocks, each of which is responsible for querying and drawing a particular type of feature.
Chameleon scripts are executed in a procedural fashion, from top to bottom. Below is an example of a very simple Chameleon script:
property name = "Demonstration Script" declare %detailLevel = 100 begin map !clearBrush = brush<(192,192,255)> !brown = (255,200,100) clear !clearBrush begin polygons render [land],brush<!brown> end polygons begin streets reversed render [super],pen<(0,0,0),2> if %scale < %detailLevel render [all],pen<(140,140,140),1> end if end streets end map
This example uses three blocks: a top-level map block, a polygons block, and a streets block. Outside the map block are two statements to set up a property that can be accessed from application code, and declare a constant for use within the map style. Inside the map block two variables are assigned, and the map is cleared using a clear statement. Finally, inside the polygon and streets blocks, render statements specify to GeoBase which features to draw and how to draw them.
A block is rendered in two phases: First there is a filter pass and then one or more render passes.
The filter pass is used to query the data to be drawn and associate them with specific render statements. During this pass a feature will be assigned to the first render whose filter it matches. This means that when a filter has been matched, further calls to that filter will be ignored. For example, say that we want to render surface streets differently to all other streets. We would need to do this:
render [surface] !surfacePen render [all] !streetPen
When the above code is called, GeoBase will render surface streets with !surfacePen, and then remove surface from the list of available filters. Thus, when render [all] is called, all other streets will be rendered with !streetPen.
Compare the above example with the one below:
render [all], !streetPen render [surface], !surfacePen
In this case, because render [all] will be called first, surface will have been removed from the list of available filters, and the call to render[surface] will have no effect.
The second phase is rendering. In the case of polygons and points, there will be only one pass. For lines, streets, and custom lines there will be a render pass for each pen on the render statement - these layers allow multiple pens on a single render statement.
In the case of multiple pens, the first pass will render all the first pens in each render block's pen list from top to bottom in order. The second pass will render all pens second in the list if any, and so on until all pens have been used.
Specifying the reversed keyword on a block enables reversed rendering. This only affects the rendering phase, the filter pass always moves from the top of the block to the bottom. The render passes will run from the bottom of the block to top.
Typically polygon blocks will render in standard order, and street blocks will be rendered in reverse order. This lets minor streets join into larger streets cleanly.