In this section we will make the map draw the point locations of our search results on the map, dynamically.
The search results are already links, that will zoom in the map when you click on them, but now they will draw a point on the map when you hover over the link.
This was by far the hardest part of the page to figure out. Hopefully this tutorial will help someone have an easier time than I did.
MapBuilder allows you to make a Feature Collection as part of your model. All feature in the feature collection will be rendered on the map using a custom rendering widget.
Here is the XML we have to add to our map_config.xml file:
<MapbuilderConfig> <models> <FeatureCollection id="featureCollection"> <defaultModelUrl>template_location.xml</defaultModelUrl> <namespace>xmlns:gml='http://www.opengis.net/gml' xmlns:wfs='http://www.opengis.net/wfs' xmlns:topp='http://www.openplans.org/topp'</namespace> <nodeSelectXpath>/gml:featureMember/topp:location/topp:the_geom/gml:MultiPoint/gml:pointMember/gml:Point/gml:coordinates</nodeSelectXpath> <widgets> <GmlRendererWZ id="testGmlRenderer"> <htmlTagId>mainMapPane</htmlTagId> <targetModel>mainMap</targetModel> <mapContainerId>mainMapContainer</mapContainerId> <lineColor>#00FF00</lineColor> <lineWidth>3</lineWidth> <pointDiameter>14</pointDiameter> </GmlRendererWZ> <FeatureList id="featureList"> </FeatureList> </widgets> </FeatureCollection> </models> </MapbuilderConfig>
The <FeatureCollection> contains a <GmlRendererWZ> widget, that will perform the rendering of the features onto the map.
All we do is point the renderer at the main map pane, set the size and color of the point to render (ignore the line values) and it will render whatever features we have in the Feature Collection.
Now you might be asking, where are the feature? Well, there aren't any right now. If you look in the <FeatureCollection> tag, there is a child tag called <FeatureList>. It is currently empty. If you fill it with GML features, they will be rendered.
Another item we have to create is an XML template for our features. To do this, make a file called template_location.xml and in it put the following XML:
<?xml version="1.0" encoding="utf-8" standalone="no"?> <gml:featureMember xmlns:topp="http://www.openplans.org/topp" xmlns:gml="http://www.opengis.net/gml"> <topp:location> <topp:the_geom> <gml:MultiPoint srsName="epsg:4326"> <gml:pointMember> <gml:Point> <gml:coordinates decimal="." cs="," ts=" "></gml:coordinates> </gml:Point> </gml:pointMember> </gml:MultiPoint> </topp:the_geom> </topp:location> </gml:featureMember>
This is how our point features will be defined. Lets tell the Feature Collection to use this template by putting the file name in the <defaultModelUrl> tag:
<defaultModelUrl>template_location.xml</defaultModelUrl>
Make sure to save the template file in the same directory as your map_config.xml file. Or, just change the path in the xml to point to where it lives.
Another thing we have to set up is the <nodeSelectXpath> value. This value is here to provide an easy, pre-defined, way for accessing the point geometry of the feature.
In the <FeatureCollection> tag, add the nodeSelectXpath tag:
<nodeSelectXpath>/gml:featureMember/topp:location/topp:the_geom/gml:MultiPoint/gml:pointMember/gml:Point/gml:coordinates</nodeSelectXpath>
I will explain the XPATH stuff next.
XPATH
All this spec is, is a way to talk down an XML structure. XML files are structured very similarly to a normal directory structure, and can be walked in the same way. Nodes have child nodes, and those nodes also have child nodes, and so on.
So to walk this following XML example:
<test> <hello> <world> <brent></brent> </world> </hwllo> </test>
The XPATH for walking this XML to get to the <brent> node is this:
/test/hello/world/brent
To get to the coordinate node in our XML template for our point feature, the XPATH value is this:
/gml:featureMember/topp:location/topp:the_geom/gml:MultiPoint/gml:pointMember/gml:Point/gml:coordinates
Everything is set now for MapBuilder to render the point. Next we have to enable it in Javascript.
Turn on the point
Lets head to the function where we print out the results from a geographic search result.
Remember where we list all the results as links in the scrollable text area? Lets go an modify the link so it has a mouseover event.
<a href="javascript:zoomto('-123.33,42.25')" onmouseover="javascript:highlightPoint('-123.33,42.25')" onmouseout="javascript:unhighlightPoint()">;
I also gave it a mouseout event that will remove the point.
Lets look at the mouseover event. Here is where we need to set the point in our FeatureCollection and tell MapBuilder to draw the point.
function highlightPoint(point)
{
success = config.objects.featureCollection.setXpathValue(config.objects.featureCollection,
config.objects.featureCollection.nodeSelectXpath,
point);
if(!success)
log("EditPoint: invalid featureXpath in config: "+config.objects.featureCollection.nodeSelectXpath);
}
In this function we access MapBuilder's configuration objects (the objects in map_config.xml) and select our feature collection.
This is done by calling config.objects.featureCollection. The FeatureCollection object has a setXpathValue() function. It takes in three parameters:
- the object to modify (yes this seems redundant)
- the xpath to find the value to change
- the new value
For the first variable, we just give it our feature collection. For the second variable, we get the xpath value from the feature collection (this is that tag we had to set <nodeSelectXpath>). For the thrid variable we set the new value: the point.
That's it.
Calling that function will set the point and automatically tell it to render. Sweet!
It's pretty easy to do once you have it set up.
Lets take a look at how MapBuilder does this. When you call setXpathValue, it will take your object and dig down the XML object structure, using the nodeSelectXpath value, and set the value of the node. When it is digging for the node, if there is no existing feature (which there isn't the first time you do this) then it will create a new one for you, and set the value for that new feature. The feature goes in the FeatureList that is part of the <FeatureCollection> element in the config file. If there is already a feature there, then the just the node value is changed and no new feature is created.
If everything goes according to plan, the function should return true and a point should appear on the map.
unhighlightPoint()
This one is pretty easy. We need to access the objects in the model (config.objects.featureCollection) and then call setHidden on it. In the function setHidden, we have to pass it two parameters:
- the object to hide (in this case the XML element <topp:location> from our template_location.xml document)
- on or off (1=on, 0=off)
config.objects.featureCollection.setHidden("topp:location",1);
And that should be it.
Now when the user hovers over the link with their mouse, a point will render at the location of where search result is in the world. When they move their mouse away, the point will dissapear.
SUMMARY
First we had to give our model, in map_config.xml, a FeatureCollection, and then we had to give the feature collection a renderer.
Next we edited the links in the search result to have mouseover and mouseout events
Then we created a function to handle the mouse over event where it would give the feature collection a new feature and set the point value of it.
Finally we created a mouseout function that would hide the existing point in the feature collection.
GmlRendererWZ is changed to GmlRendererOL in MapBuilder 1.5 rc2.
how to draw point with new renderer now.