source: subversion/utils/osmarender/osmarender.xsl @ 1824

Last change on this file since 1824 was 1824, checked in by jochen, 14 years ago

New version 3.2 with several bug fixes:

Added svg namespace to marker elements (Joto)
Added rendering for place=suburb (same as place=village) (Joto)
Added optional "osmfile" parameter to XSL stylesheet which can be used to override default filename for OSM data file (Joto)
Changed rendering order of motorway|trunk|primary[_link] (Joto)
Added icon for amenity=post_box (currently same as post_office) (Joto)
Now draws name for highway=track if available (Joto)
Added call to copyAttributes template to a use element for ways, dashed railway lines and steps now work properly (Joto)
highway=gate was rendered way to large. Icon simplified and made smaller (Joto)

File size: 65.4 KB
Line 
1<?xml version='1.0' encoding='UTF-8' ?>
2<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp '&#160;'> ]>
3
4<!-- Osmarender.xsl 3.2 -->
5
6<!-- Revision history:
7     1.0 2006-03-21 Initial version
8     1.1 2006-03-23 Remove <html> and <body> tags
9     1.2 2006-03-24 Support for ways
10     1.3 2006-04-10 width key will override line width
11                    Implements nested rules
12                    General restructuring
13                    Implements <symbol> instruction
14                 1.4 2006-04-11 Implements <textPath> instruction for text on Segments and Ways
15                 1.5 2006-04-11 Fix bug that generated invalid xsl-stylesheet PI
16                                                                                Fix bug resulting in superflous white space output
17                                                                                Fix bug causing dy attribute on <textPath> element rather than <text> element
18     1.6 2006-04-12 Fix bug with <text> instructions choking on <segment> and <way> elements in Batik
19     2.0 2006-07-07 Implements <area> instruction for areas and ways
20                    Fix bug to enable stroke-linecap="butt"
21                                        Implements e attribute for rules, allowing selection by element type
22                    Implements v="*" for rules
23                    Implements k="*" for rules
24                    Implements e="node|segment|way|area" for rules
25                    Implements v="rag|tag|bobtail" for rules
26                    Implements k="rag|tag|bobtail" for rules
27                                        Generates progress message as each rule is processed
28                                        Elements with tags that have a key starting with svg: will be applied to the corresponding rendered element
29                                        Use of width key (eg <tag k="width" v="5px"/>) desupported in favour of svg:stroke-width (eg <tag k="svg:stroke-width" v="5px"/>
30                                        Use of x-offset and y-offset attributes desupported in favour of dx and dy for <text> instructions and transform='translate(x,y)'
31                                                for <symbol> instructions.
32                                        Implements name_direction='-1' tag on segments and ways to draw street names in the reverse direction.
33                                        Use of <textPath> instruction desupported in favour of <text> instruction which now does the right thing for both segments and ways.                           
34                                        Copyright and attribution captions dynamically re-positioned top-left. 
35     3.0 2006-09-23 Fix bug with non-contiguous segments in an area
36                                        Ignore elements with action='delete' for use with locally edited JOSM files
37                                        Apply linked segment optimisation to ways that have name_direction=-1
38                                        Added a switch to make copyright and attribution stuff optional
39                                        Made copyright and attribution stuff smaller
40                                        Fix bug with butt-capped ways that abut each other and caused cracks in roads
41                                        Fix bug with butt-capped ways and name_direction=-1 that caused cracks in roads
42                                        Implements layering using the layer tag.
43                                        Implements approximate mercator projection.
44                                        Implements pan and zoom controls.
45                                        Implement border and 1km square grid.
46                                        Implements osmarender:nameDirection as a preferred alternative to name_direction
47                                        <bounds> element in rules file allows bounding box of map to be specified
48                                        <bounds> element in .osm file allows bounding box of map to be specified
49                                        Improved rules file, lots of new tags, icons and cleaner look and feel
50                                        Rules file does not select segments for rendering by default (this encourages everyone to tag ways)
51                                        Tested with IE 6.x, Firefox 1.5, xalan, xmlstarlet, xsltproc, Adobe ASV3, Inkscape, Batik-Squiggle
52        3.1 2006-09-30  Implements waysegment pseudo-element to enable segments that are part of a way to be selected
53                                        Grid lines are now generated properly
54                                        Rendering of external white border is now improved when bounds are specified
55                                        No external white border when no bounds specified
56                                        Various tweaks to the rules file
57    3.2 2006-12-29  Added svg namespace to marker elements (Joto)
58                    Added rendering for place=suburb (same as place=village) (Joto)
59                    Added optional "osmfile" parameter to XSL stylesheet which can be used to override default filename for OSM data file (Joto)
60                    Changed rendering order of motorway|trunk|primary[_link] (Joto)
61                    Added icon for amenity=post_box (currently same as post_office) (Joto)
62                    Now draws name for highway=track if available (Joto)
63                    Added call to copyAttributes template to a use element for ways, dashed railway lines and steps now work properly (Joto)
64                    highway=gate was rendered way to large. Icon simplified and made smaller (Joto)
65-->
66
67<!-- Osmarender rules files contain two kinds of element; rules and instructions.  Rule elements provide a
68     simple selection mechanism.  Instructions define what to do with the elements that match the rules.
69     
70     Rules are simple filters based on elements, keys and values (the e, k and v attributes).  For example:
71      <rule e="way" k="highway" v="motorway">...</rule>
72     will select all ways that have a key of highway with a value of motorway.
73     Rules can be nested to provide a logical "and".  For example:
74       <rule e="way" k="highway" v="primary">
75         <rule e="way" k="abutters" v="retail">
76          ...
77         </rule>
78       </rule>
79     would select all ways that are primary roads *and* abutted by retail premises.
80
81         Each filter attribute can contain a | separated list of values.  For example e="node|way" will match all nodes and all ways. 
82         k="highway|waterway" will match all elements with a key of highway or waterway. v="primary|secondary" will match all elements that
83         have key values equal to primary or secondary. k="*" means all keys.  k="~" means no keys.  v="*" means all values. v="~" means no value.
84             
85     Instructions define what to do with the elements that match the rules.  Typically, they render the element
86     in some way by generating an svg command to draw a line or circle etc.  In most cases the attributes of
87     the instruction are copied to the corresponding svg command.  For example:
88       <line stroke-width="10"/>
89     will generate a corresponding svg command to draw a line with a width of 10px.
90     The following instructions can be used:
91       <line>   - draw a line
92       <area>   - draw an area
93       <circle> - draw a circle
94       <text>   - write some text
95       <symbol> - draw an icon or image
96-->
97
98<xsl:stylesheet 
99 version="1.0"
100 xmlns="http://www.w3.org/2000/svg"
101 xmlns:xlink="http://www.w3.org/1999/xlink"
102 xmlns:ev="http://www.w3.org/2001/xml-events"
103 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
104 
105        <xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="UTF-8"/>
106
107    <xsl:param name="osmfile" value="/rules/@data"/>
108
109        <xsl:key name='nodeById' match='/osm/node' use='@id'/>
110        <xsl:key name='segmentById' match='/osm/segment' use='@id'/>
111        <xsl:key name='segmentByFromNode' match='/osm/segment' use='@from'/>
112        <xsl:key name='segmentByToNode' match='/osm/segment' use='@to'/>
113        <xsl:key name='wayBySegment' match='/osm/way' use='seg/@id'/>
114       
115        <xsl:variable name='data' select='document($osmfile)'/>
116
117        <!-- Calculate the size of the bounding box based on the file content -->
118        <xsl:variable name="bllat">
119                <xsl:for-each select="$data/osm/node/@lat">
120                        <xsl:sort data-type="number" order="ascending"/>
121                        <xsl:if test="position()=1">
122                                <xsl:value-of select="."/>
123                        </xsl:if>
124                </xsl:for-each>
125        </xsl:variable>
126        <xsl:variable name="bllon">
127                <xsl:for-each select="$data/osm/node/@lon">
128                        <xsl:sort data-type="number" order="ascending"/>
129                        <xsl:if test="position()=1">
130                                <xsl:value-of select="."/>
131                        </xsl:if>
132                </xsl:for-each>
133        </xsl:variable>
134        <xsl:variable name="trlat">
135                <xsl:for-each select="$data/osm/node/@lat">
136                        <xsl:sort data-type="number" order="descending"/>
137                        <xsl:if test="position()=1">
138                                <xsl:value-of select="."/>
139                        </xsl:if>
140                </xsl:for-each>
141        </xsl:variable>
142        <xsl:variable name="trlon">
143                <xsl:for-each select="$data/osm/node/@lon">
144                        <xsl:sort data-type="number" order="descending"/>
145                        <xsl:if test="position()=1">
146                                <xsl:value-of select="."/>
147                        </xsl:if>
148                </xsl:for-each>
149        </xsl:variable>
150       
151        <xsl:variable name="bottomLeftLatitude">
152                <xsl:choose>
153                        <xsl:when test='/rules/bounds'>
154                                <xsl:value-of select='/rules/bounds/@minlat'/>
155                        </xsl:when>
156                        <xsl:when test='$data/osm/bounds'>
157                                <xsl:value-of select='$data/osm/bounds/@request_minlat'/>
158                        </xsl:when>
159                        <xsl:otherwise>
160                                <xsl:value-of select='$bllat'/>
161                        </xsl:otherwise>               
162                </xsl:choose>
163        </xsl:variable>
164        <xsl:variable name="bottomLeftLongitude">
165                <xsl:choose>
166                        <xsl:when test='/rules/bounds'>
167                                <xsl:value-of select='/rules/bounds/@minlon'/>
168                        </xsl:when>
169                        <xsl:when test='$data/osm/bounds'>
170                                <xsl:value-of select='$data/osm/bounds/@request_minlon'/>
171                        </xsl:when>
172                        <xsl:otherwise>
173                                <xsl:value-of select='$bllon'/>
174                        </xsl:otherwise>               
175                </xsl:choose>
176        </xsl:variable>
177        <xsl:variable name="topRightLatitude">
178                <xsl:choose>
179                        <xsl:when test='/rules/bounds'>
180                                <xsl:value-of select='/rules/bounds/@maxlat'/>
181                        </xsl:when>
182                        <xsl:when test='$data/osm/bounds'>
183                                <xsl:value-of select='$data/osm/bounds/@request_maxlat'/>
184                        </xsl:when>
185                        <xsl:otherwise>
186                                <xsl:value-of select='$trlat'/>
187                        </xsl:otherwise>               
188                </xsl:choose>
189        </xsl:variable>
190        <xsl:variable name="topRightLongitude">
191                <xsl:choose>
192                        <xsl:when test='/rules/bounds'>
193                                <xsl:value-of select='/rules/bounds/@maxlon'/>
194                        </xsl:when>
195                        <xsl:when test='$data/osm/bounds'>
196                                <xsl:value-of select='$data/osm/bounds/@request_maxlon'/>
197                        </xsl:when>
198                        <xsl:otherwise>
199                                <xsl:value-of select='$trlon'/>
200                        </xsl:otherwise>               
201                </xsl:choose>
202        </xsl:variable>
203
204        <xsl:variable name='scale' select='/rules/@scale'/>
205
206        <!-- Derive the latitude of the middle of the map -->
207        <xsl:variable name='middleLatitude' select='($topRightLatitude + $bottomLeftLatitude) div 2.0'/>
208        <!--woohoo lets do trigonometry in xslt -->
209        <!--convert latitude to radians -->
210        <xsl:variable name='latr' select='$middleLatitude * 3.1415926 div 180.0' />
211        <!--taylor series: two terms is 1% error at lat<68 and 10% error lat<83. we probably need polar projection by then -->
212        <xsl:variable name='coslat' select='1 - ($latr * $latr) div 2 + ($latr * $latr * $latr * $latr) div 24' />
213        <xsl:variable name='projection' select='1 div $coslat' />
214
215        <xsl:variable name='dataWidth' select='(number($topRightLongitude)-number($bottomLeftLongitude))*10000*$scale' />
216        <xsl:variable name='dataHeight' select='(number($topRightLatitude)-number($bottomLeftLatitude))*10000*$scale*$projection' />
217        <xsl:variable name='km' select='(0.0089928*$scale*10000*$projection)' />
218        <xsl:variable name='documentWidth'>
219                <xsl:choose>
220                        <xsl:when test='$dataWidth &gt; (number(/rules/@minimumMapWidth) * $km)'>
221                                <xsl:value-of select='$dataWidth'/>
222                        </xsl:when>
223                        <xsl:otherwise><xsl:value-of select='number(/rules/@minimumMapWidth) * $km'/></xsl:otherwise>
224                </xsl:choose>
225        </xsl:variable>
226        <xsl:variable name='documentHeight'>
227                <xsl:choose>
228                        <xsl:when test='$dataHeight &gt; (number(/rules/@minimumMapHeight) * $km)'>
229                                <xsl:value-of select='$dataHeight'/>
230                        </xsl:when>
231                        <xsl:otherwise><xsl:value-of select='number(/rules/@minimumMapHeight) * $km'/></xsl:otherwise>
232                </xsl:choose>
233        </xsl:variable>
234        <xsl:variable name='width' select='($documentWidth div 2) + ($dataWidth div 2)'/>
235        <xsl:variable name='height' select='($documentHeight div 2) + ($dataHeight div 2)'/>
236
237        <!-- Main template -->
238        <xsl:template match="/rules">     
239
240                <!-- Include an external css stylesheet if one was specified in the rules file -->
241                <xsl:if test='@xml-stylesheet'>
242                        <xsl:processing-instruction name='xml-stylesheet'>
243                                href="<xsl:value-of select='@xml-stylesheet'/>" type="text/css"
244                        </xsl:processing-instruction>
245                </xsl:if>
246
247                <svg
248                 id='main'
249                 version="1.1"
250                 baseProfile="full"
251                 height="100%"
252                 width="100%">         
253                        <xsl:if test='/rules/@javaScript="yes"'>
254                                <xsl:attribute name='onscroll'>fnOnScroll(evt)</xsl:attribute>
255                                <xsl:attribute name='onzoom'>fnOnZoom(evt)</xsl:attribute>
256                                <xsl:attribute name='onload'>fnOnLoad(evt)</xsl:attribute>
257                                <xsl:attribute name='onmousedown'>fnOnMouseDown(evt)</xsl:attribute>
258                                <xsl:attribute name='onmousemove'>fnOnMouseMove(evt)</xsl:attribute>
259                                <xsl:attribute name='onmouseup'>fnOnMouseUp(evt)</xsl:attribute>
260                        </xsl:if>
261
262                        <!-- Include javaScript functions for all the dynamic stuff --> 
263                        <xsl:if test='/rules/@javaScript="yes"'>
264                                <xsl:call-template name='javaScript'/>
265                        </xsl:if>
266
267                        <defs>                         
268                                <!-- Get any <defs> and styles from the rules file -->
269                                <xsl:copy-of select='defs/*'/>
270                        </defs>
271
272                        <!-- Pre-generate named path definitions for all ways -->
273                        <xsl:variable name='allWays' select='$data/osm/way' />
274                        <defs>
275                                <xsl:for-each select='$allWays'>
276                                        <xsl:call-template name='generateWayPath'/>
277                                </xsl:for-each>
278                        </defs>
279
280
281                        <!-- Draw a nice background layer -->
282                        <rect x='0px' y='0px' height='{$documentHeight}px' width='{$documentWidth}px' class='map-background'/>
283
284
285                        <!-- Process all the rules, one layer at a time -->
286                                <xsl:apply-templates select='/rules/rule'>
287                                        <xsl:with-param name='elements' select='$data/osm/*[not(@action="delete") and tag[@k="layer" and @v="-5"]]' />
288                                        <xsl:with-param name='layer' select='"-5"' />
289                                </xsl:apply-templates>
290                                <xsl:apply-templates select='/rules/rule'>
291                                        <xsl:with-param name='elements' select='$data/osm/*[not(@action="delete") and tag[@k="layer" and @v="-4"]]' />
292                                        <xsl:with-param name='layer' select='"-4"' />
293                                </xsl:apply-templates>
294                                <xsl:apply-templates select='/rules/rule'>
295                                        <xsl:with-param name='elements' select='$data/osm/*[not(@action="delete") and tag[@k="layer" and @v="-3"]]' />
296                                        <xsl:with-param name='layer' select='"-3"' />
297                                </xsl:apply-templates>
298                                <xsl:apply-templates select='/rules/rule'>
299                                        <xsl:with-param name='elements' select='$data/osm/*[not(@action="delete") and tag[@k="layer" and @v="-2"]]' />
300                                        <xsl:with-param name='layer' select='"-2"' />
301                                </xsl:apply-templates>
302                                <xsl:apply-templates select='/rules/rule'>
303                                        <xsl:with-param name='elements' select='$data/osm/*[not(@action="delete") and tag[@k="layer" and @v="-1"]]' />
304                                        <xsl:with-param name='layer' select='"-1"' />
305                                </xsl:apply-templates>
306                                <xsl:apply-templates select='/rules/rule'>
307                                        <xsl:with-param name='elements' select='$data/osm/*[not(@action="delete") and count(tag[@k="layer"])=0 or tag[@k="layer" and @v="0"]]' />
308                                        <xsl:with-param name='layer' select='"0"' />
309                                </xsl:apply-templates>
310                                <xsl:apply-templates select='/rules/rule'>
311                                        <xsl:with-param name='elements' select='$data/osm/*[not(@action="delete") and tag[@k="layer" and @v="1"]]' />
312                                        <xsl:with-param name='layer' select='"1"' />
313                                </xsl:apply-templates>
314                                <xsl:apply-templates select='/rules/rule'>
315                                        <xsl:with-param name='elements' select='$data/osm/*[not(@action="delete") and tag[@k="layer" and @v="2"]]' />
316                                        <xsl:with-param name='layer' select='"2"' />
317                                </xsl:apply-templates>
318                                <xsl:apply-templates select='/rules/rule'>
319                                        <xsl:with-param name='elements' select='$data/osm/*[not(@action="delete") and tag[@k="layer" and @v="3"]]' />
320                                        <xsl:with-param name='layer' select='"3"' />
321                                </xsl:apply-templates>
322                                <xsl:apply-templates select='/rules/rule'>
323                                        <xsl:with-param name='elements' select='$data/osm/*[not(@action="delete") and tag[@k="layer" and @v="4"]]' />
324                                        <xsl:with-param name='layer' select='"4"' />
325                                </xsl:apply-templates>
326                                <xsl:apply-templates select='/rules/rule'>
327                                        <xsl:with-param name='elements' select='$data/osm/*[not(@action="delete") and tag[@k="layer" and @v="5"]]' />
328                                        <xsl:with-param name='layer' select='"5"' />
329                                </xsl:apply-templates>
330                       
331       
332                        <!-- Blank out anything outside the bounding box -->
333                        <xsl:if test='/rules/bounds or $data/osm/bounds'>
334                                <xsl:call-template name='eraseOutsideBoundingBox'/>
335                        </xsl:if>
336                       
337                        <!-- Draw a grid if required -->
338                        <xsl:if test='/rules/@showGrid="yes"'>
339                                <xsl:call-template name="gridDraw"/>
340                        </xsl:if>
341
342                        <!-- Draw a border if required -->
343                        <xsl:if test='/rules/@showBorder="yes"'>
344                                <xsl:call-template name="borderDraw"/>
345                        </xsl:if>
346
347                        <!-- Draw the scale in the bottom left corner -->
348                        <xsl:if test='/rules/@showScale="yes"'>
349                                <xsl:call-template name="scaleDraw"/>
350                        </xsl:if>
351
352                        <!-- Draw labels and controls that are in a static position -->
353                        <g id="staticElements" transform="scale(1) translate(0,0)">
354                                <!-- Draw the +/- zoom controls -->
355                                <xsl:if test='/rules/@showZoomControls="yes"'>
356                                        <xsl:call-template name="zoomControl"/>
357                                </xsl:if>
358
359                                <!-- Attribute to OSM -->
360                                <xsl:if test='/rules/@showAttribution="yes"'>
361                                        <xsl:call-template name="attribution"/>
362                                </xsl:if>
363                               
364                                <!-- Creative commons license -->
365                                <xsl:if test='/rules/@showLicense="yes"'>
366                                        <xsl:call-template name="license"/>
367                                </xsl:if>
368                        </g>
369                </svg>
370
371        </xsl:template>
372
373
374        <!-- ============================================================================= -->
375        <!-- Rule processing template                                                      -->
376        <!-- ============================================================================= -->
377
378        <!-- For each rule apply line, circle, text, etc templates.  Then apply the rule template recursively for each nested rule --> 
379        <xsl:template match='rule'>
380                <xsl:param name='elements' />
381                <xsl:param name='layer' />
382
383                <!-- This is the rule currently being processed -->
384                <xsl:variable name='rule' select='.'/>
385
386                <!-- Make list of elements that this rule should be applied to -->
387                <xsl:variable name='eBare'>
388                        <xsl:choose>
389                                <xsl:when test='$rule/@e="*"'>node|segment|way|area</xsl:when>
390                                <xsl:when test='$rule/@e'><xsl:value-of select='$rule/@e'/></xsl:when>
391                                <xsl:otherwise>node|segment|way|area</xsl:otherwise>
392                        </xsl:choose>
393                </xsl:variable>
394
395                <!-- List of keys that this rule should be applied to -->
396                <xsl:variable name='kBare' select='$rule/@k' />
397
398                <!-- List of values that this rule should be applied to -->
399                <xsl:variable name='vBare' select='$rule/@v' />
400
401                <!-- Top'n'tail selectors with | for contains usage -->
402                <xsl:variable name='e'>|<xsl:value-of select='$eBare'/>|</xsl:variable>
403                <xsl:variable name='k'>|<xsl:value-of select='$kBare'/>|</xsl:variable>
404                <xsl:variable name='v'>|<xsl:value-of select='$vBare'/>|</xsl:variable>
405
406
407                <xsl:variable name='selectedElements' select='$elements[contains($e,concat("|",name(),"|"))or (contains($e,"|waysegment|") and name()="segment" and key("wayBySegment",@id))]'/>
408
409                <xsl:choose>
410                        <xsl:when test='contains($k,"|*|")'>
411                                <xsl:choose>
412                                        <xsl:when test='contains($v,"|~|")'>
413                                                <xsl:variable name='elementsWithNoTags' select='$selectedElements[count(tag)=0]'/>
414                                                <xsl:call-template name='processElements'>
415                                                        <xsl:with-param name='eBare' select='$eBare'/>
416                                                        <xsl:with-param name='kBare' select='$kBare'/>
417                                                        <xsl:with-param name='vBare' select='$vBare'/>
418                                                        <xsl:with-param name='layer' select='$layer'/>
419                                                        <xsl:with-param name='elements' select='$elementsWithNoTags'/>
420                                                        <xsl:with-param name='rule' select='$rule'/>
421                                                </xsl:call-template>
422                                        </xsl:when>
423                                        <xsl:when test='contains($v,"|*|")'>
424                                                <xsl:variable name='allElements' select='$selectedElements'/>
425                                                <xsl:call-template name='processElements'>
426                                                        <xsl:with-param name='eBare' select='$eBare'/>
427                                                        <xsl:with-param name='kBare' select='$kBare'/>
428                                                        <xsl:with-param name='vBare' select='$vBare'/>
429                                                        <xsl:with-param name='layer' select='$layer'/>
430                                                        <xsl:with-param name='elements' select='$allElements'/>
431                                                        <xsl:with-param name='rule' select='$rule'/>
432                                                </xsl:call-template>
433                                        </xsl:when>
434                                        <xsl:otherwise>
435                                                <xsl:variable name='allElementsWithValue' select='$selectedElements[tag[contains($v,concat("|",@v,"|"))]]'/>
436                                                <xsl:call-template name='processElements'>
437                                                        <xsl:with-param name='eBare' select='$eBare'/>
438                                                        <xsl:with-param name='kBare' select='$kBare'/>
439                                                        <xsl:with-param name='vBare' select='$vBare'/>
440                                                        <xsl:with-param name='layer' select='$layer'/>
441                                                        <xsl:with-param name='elements' select='$allElementsWithValue'/>
442                                                        <xsl:with-param name='rule' select='$rule'/>
443                                                </xsl:call-template>
444                                        </xsl:otherwise>
445                                </xsl:choose>
446                        </xsl:when>
447                        <xsl:when test='contains($v,"|~|")'>
448                                <xsl:variable name='elementsWithoutKey' select='$selectedElements[count(tag[contains($k,concat("|",@k,"|"))])=0]'/>
449                                <xsl:call-template name='processElements'>
450                                        <xsl:with-param name='eBare' select='$eBare'/>
451                                        <xsl:with-param name='kBare' select='$kBare'/>
452                                        <xsl:with-param name='vBare' select='$vBare'/>
453                                        <xsl:with-param name='layer' select='$layer'/>
454                                        <xsl:with-param name='elements' select='$elementsWithoutKey'/>
455                                        <xsl:with-param name='rule' select='$rule'/>
456                                </xsl:call-template>
457                        </xsl:when>
458                        <xsl:when test='contains($v,"|*|")'>
459                                <xsl:variable name='allElementsWithKey' select='$selectedElements[tag[contains($k,concat("|",@k,"|"))]]'/>
460                                <xsl:call-template name='processElements'>
461                                        <xsl:with-param name='eBare' select='$eBare'/>
462                                        <xsl:with-param name='kBare' select='$kBare'/>
463                                        <xsl:with-param name='vBare' select='$vBare'/>
464                                        <xsl:with-param name='layer' select='$layer'/>
465                                        <xsl:with-param name='elements' select='$allElementsWithKey'/>
466                                        <xsl:with-param name='rule' select='$rule'/>
467                                </xsl:call-template>
468                        </xsl:when>
469                        <xsl:otherwise>
470                                <xsl:variable name='elementsWithKey' select='$selectedElements[tag[contains($k,concat("|",@k,"|")) and contains($v,concat("|",@v,"|"))]]'/>
471                                <xsl:call-template name='processElements'>
472                                        <xsl:with-param name='eBare' select='$eBare'/>
473                                        <xsl:with-param name='kBare' select='$kBare'/>
474                                        <xsl:with-param name='vBare' select='$vBare'/>
475                                        <xsl:with-param name='layer' select='$layer'/>
476                                        <xsl:with-param name='elements' select='$elementsWithKey'/>
477                                        <xsl:with-param name='rule' select='$rule'/>
478                                </xsl:call-template>
479                        </xsl:otherwise>
480                </xsl:choose>
481        </xsl:template>
482
483
484        <!-- Process a set of elements selected by a rule at a specific layer -->
485        <xsl:template name='processElements'>
486                <xsl:param name='eBare'/>
487                <xsl:param name='kBare'/>
488                <xsl:param name='vBare'/>
489                <xsl:param name='layer'/>
490                <xsl:param name='elements'/>
491                <xsl:param name='rule'/>
492               
493                <xsl:if test='$elements'>
494                        <xsl:message>
495Processing &lt;rule e="<xsl:value-of select='$eBare'/>" k="<xsl:value-of select='$kBare'/>" v="<xsl:value-of select='$vBare'/>" &gt; 
496Matched by <xsl:value-of select='count($elements)'/> elements for layer <xsl:value-of select='$layer'/>.
497                        </xsl:message>
498
499                        <xsl:apply-templates select='*'>
500                                <xsl:with-param name='layer' select='$layer' />
501                                <xsl:with-param name='elements' select='$elements' />
502                                <xsl:with-param name='rule' select='$rule'/>
503                        </xsl:apply-templates>
504                </xsl:if>
505        </xsl:template>
506
507
508        <!-- ============================================================================= -->
509        <!-- Templates to process line, circle, text, etc instructions                     -->
510        <!-- ============================================================================= -->
511        <!-- Each template is passed a variable containing the set of elements that need to
512             be processed.  The set of elements is already determined by the rules, so
513             these templates don't need to know anything about the rules context they are in. -->
514
515        <!-- Process a <line> instruction -->
516        <xsl:template match='line'>
517                <xsl:param name='elements' />
518                <xsl:param name='layer' />
519
520                <!-- This is the instruction that is currently being processed -->
521                <xsl:variable name='instruction' select='.'/>
522
523                <g>
524                        <xsl:apply-templates select='@*' mode='copyAttributes'/> <!-- Add all the svg attributes of the <line> instruction to the <g> element -->
525
526                        <!-- For each segment and way -->
527                        <xsl:apply-templates select='$elements' mode='line'>
528                                <xsl:with-param name='instruction' select='$instruction' />
529                                <xsl:with-param name='layer' select='$layer' />
530                        </xsl:apply-templates>
531
532                </g>
533        </xsl:template>
534
535
536        <!-- Suppress output of any unhandled elements -->
537        <xsl:template match='*' mode='line'/>
538       
539       
540        <!-- Draw lines for a segment -->
541        <xsl:template match='segment' mode='line'>
542                <xsl:param name='instruction' />
543
544                <xsl:call-template name='drawLine'>
545                        <xsl:with-param name='instruction' select='$instruction'/>
546                        <xsl:with-param name='segment' select='.'/>
547                </xsl:call-template>
548
549        </xsl:template>
550
551
552        <!-- Draw lines for a way (draw all the segments that belong to the way) -->
553        <xsl:template match='way' mode='line'>
554                <xsl:param name='instruction' />
555                <xsl:param name='layer' />
556
557                <!-- The current <way> element -->
558                <xsl:variable name='way' select='.' />
559               
560                <xsl:call-template name='drawWay'>
561                        <xsl:with-param name='instruction' select='$instruction'/>
562                        <xsl:with-param name='way' select='$way'/>
563                        <xsl:with-param name='layer' select='$layer' />
564                </xsl:call-template>
565
566        </xsl:template>
567       
568
569        <!-- Process an <area> instruction -->
570        <xsl:template match='area'>
571                <xsl:param name='elements' />
572
573                <!-- This is the instruction that is currently being processed -->
574                <xsl:variable name='instruction' select='.'/>
575
576                <g>
577                        <xsl:apply-templates select='@*' mode='copyAttributes'/> <!-- Add all the svg attributes of the <line> instruction to the <g> element -->
578
579                        <!-- For each segment and way -->
580                        <xsl:apply-templates select='$elements' mode='area'>
581                                <xsl:with-param name='instruction' select='$instruction' />
582                        </xsl:apply-templates>
583
584                </g>
585        </xsl:template>
586
587
588        <!-- Suppress output of any unhandled elements -->
589        <xsl:template match='*' mode='area'/>
590       
591       
592        <!-- Draw area for a <way> or an <area> -->
593        <xsl:template match='way|area' mode='area'>
594                <xsl:param name='instruction' />
595
596                <xsl:call-template name='generateAreaPath' />
597
598                <xsl:call-template name='renderArea'>
599                        <xsl:with-param name='instruction' select='$instruction'/>
600                        <xsl:with-param name='pathId' select='concat("area_",@id)'/>
601                </xsl:call-template>
602
603        </xsl:template>
604
605
606        <!-- Process circle instruction -->
607        <xsl:template match='circle'>
608                <xsl:param name='elements'/>
609
610                <!-- This is the instruction that is currently being processed -->
611                <xsl:variable name='instruction' select='.' />
612
613                <xsl:for-each select='$elements[name()="node"]'>
614                        <xsl:call-template name='drawCircle'>
615                                <xsl:with-param name='instruction' select='$instruction'/>
616                        </xsl:call-template>                                   
617                </xsl:for-each>
618        </xsl:template>
619
620
621        <!-- Process a symbol instruction -->
622        <xsl:template match='symbol'>
623                <xsl:param name='elements'/>
624
625                <!-- This is the instruction that is currently being processed -->
626                <xsl:variable name='instruction' select='.' />
627
628                <xsl:for-each select='$elements[name()="node"]'>
629                        <xsl:call-template name='drawSymbol'>
630                                <xsl:with-param name='instruction' select='$instruction'/>
631                        </xsl:call-template>
632                </xsl:for-each>
633        </xsl:template> 
634
635
636        <!-- Process a <text> instruction -->
637        <xsl:template match='text'>
638                <xsl:param name='elements'/>
639
640                <!-- This is the instruction that is currently being processed -->
641                <xsl:variable name='instruction' select='.' />
642               
643                <!-- Select all <node> elements that have a key that matches the k attribute of the text instruction -->
644                <xsl:for-each select='$elements[name()="node"][tag[@k=$instruction/@k]]'>
645                                <xsl:call-template name='renderText'>
646                                        <xsl:with-param name='instruction' select='$instruction'/>
647                                </xsl:call-template>                                   
648                </xsl:for-each>
649
650                <!-- Select all <segment> and <way> elements that have a key that matches the k attribute of the text instruction -->
651                <xsl:apply-templates select='$elements[name()="segment" or name()="way"][tag[@k=$instruction/@k]]' mode='textPath'>
652                        <xsl:with-param name='instruction' select='$instruction' />
653                </xsl:apply-templates>
654        </xsl:template>
655
656
657        <!-- Suppress output of any unhandled elements -->
658        <xsl:template match='*' mode='textPath'/>
659
660
661        <!-- Render textPaths for a segment -->
662        <xsl:template match='segment' mode='textPath'>
663                <xsl:param name='instruction' />
664               
665                <!-- The current <segment> element -->
666                <xsl:variable name='segment' select='.' />
667
668                <!-- Generate the path for the segment -->
669                <!-- Text on segments should be relatively uncommon so only generate a <path> when one is needed -->
670                <xsl:call-template name='generateSegmentPath' />
671
672                <xsl:call-template name='renderTextPath'>
673                        <xsl:with-param name='instruction' select='$instruction'/>
674                        <xsl:with-param name='pathId' select='concat("segment_",@id)'/>
675                </xsl:call-template>
676
677        </xsl:template>
678
679
680        <!-- Render textPaths for a way -->
681        <xsl:template match='way' mode='textPath'>
682                <xsl:param name='instruction' />
683
684                <!-- The current <way> element -->
685                <xsl:variable name='way' select='.' />
686
687                <xsl:call-template name='renderTextPath'>
688                        <xsl:with-param name='instruction' select='$instruction'/>
689                        <xsl:with-param name='pathId' select='concat("way_",@id)'/>
690                </xsl:call-template>
691
692        </xsl:template>
693
694
695        <!-- Generate a way path for the current segment -->
696        <xsl:template name='generateSegmentPath'>
697                <xsl:variable name='pathData'>
698                        <xsl:choose>
699                                <xsl:when test='tag[@k="name_direction"]/@v="-1" or tag[@k="osmarender:nameDirection"]/@v="-1"'>
700                                        <xsl:call-template name='segmentMoveToEnd'/>
701                                        <xsl:call-template name='segmentLineToStart'/>
702                                </xsl:when>
703                                <xsl:otherwise>
704                                        <xsl:call-template name='segmentMoveToStart'/>
705                                        <xsl:call-template name='segmentLineToEnd'/>                   
706                                </xsl:otherwise>
707                        </xsl:choose>
708                </xsl:variable>
709
710                <path id="segment_{@id}" d="{$pathData}"/>
711
712        </xsl:template>
713
714
715        <!-- Generate a way path for the current way element -->
716        <xsl:template name='generateWayPath'>
717               
718                <!-- Generate the path for the way -->
719                <xsl:variable name='pathData'>
720                        <xsl:choose>
721                                <xsl:when test='tag[@k="name_direction"]/@v="-1" or tag[@k="osmarender:nameDirection"]/@v="-1"'>
722                                        <xsl:for-each select='seg'>
723                                                <xsl:sort select='position()' data-type='number' order='descending'/>
724                                                <xsl:variable name='segmentId' select='@id'/>
725                                                <xsl:variable name='linkedSegment' select='key("segmentById",following-sibling::seg[1]/@id)/@from=key("segmentById",@id)/@to'/>
726                                                <xsl:for-each select='key("segmentById",$segmentId)'>
727                                                        <xsl:if test='not($linkedSegment)'>
728                                                                <xsl:call-template name='segmentMoveToEnd'/>
729                                                        </xsl:if>
730                                                                <xsl:call-template name='segmentLineToStart'/>
731                                                </xsl:for-each>
732                                        </xsl:for-each>                         
733                                </xsl:when>
734                                <xsl:otherwise>
735                                        <xsl:for-each select='seg[key("segmentById",@id)]'>
736                                                <xsl:variable name='segmentId' select='@id'/>
737                                                <xsl:variable name='linkedSegment' select='key("segmentById",@id)/@from=key("segmentById",preceding-sibling::seg[1]/@id)/@to'/>
738                                                <xsl:for-each select='key("segmentById",$segmentId)'>
739                                                        <xsl:if test='not($linkedSegment)'>
740                                                                <xsl:call-template name='segmentMoveToStart'/>                         
741                                                        </xsl:if>
742                                                                <xsl:call-template name='segmentLineToEnd'/>                                                   
743                                                </xsl:for-each>
744                                        </xsl:for-each>                         
745                                </xsl:otherwise>                       
746                        </xsl:choose>
747                </xsl:variable>
748
749                <path id="way_{@id}" d="{$pathData}"/>
750
751        </xsl:template>
752
753
754        <!-- Generate an area path for the current way or area element -->
755        <xsl:template name='generateAreaPath'>
756
757                <!-- Generate the path for the area -->
758                <xsl:variable name='pathData'>
759                        <xsl:for-each select='seg[key("segmentById",@id)]'>
760                                <xsl:variable name='segmentId' select='@id'/>
761                                <xsl:variable name='linkedSegment' select='key("segmentById",@id)/@from=key("segmentById",preceding-sibling::seg[1]/@id)/@to'/>
762                                <xsl:variable name='segmentSequence' select='position()'/>
763                                <xsl:for-each select='key("segmentById",$segmentId)'>
764                                                <xsl:if test='$segmentSequence=1'>
765                                                        <xsl:call-template name='segmentMoveToStart'/>                         
766                                                </xsl:if>
767                                                <xsl:if test='not($linkedSegment)'>
768                                                        <xsl:call-template name='segmentLineToStart'/>                         
769                                                </xsl:if>
770                                                <xsl:call-template name='segmentLineToEnd'/>
771                                </xsl:for-each>
772                        </xsl:for-each>
773                        <xsl:text>Z</xsl:text>
774                </xsl:variable>
775
776                <path id="area_{@id}" d="{$pathData}"/>
777
778        </xsl:template>
779
780
781        <!-- Generate a MoveTo command for a segment start -->
782        <xsl:template name='segmentMoveToStart'>
783                <xsl:variable name='from' select='@from'/>
784                <xsl:variable name='fromNode' select='key("nodeById",$from)'/>
785
786                <xsl:variable name='x1' select='($width)-((($topRightLongitude)-($fromNode/@lon))*10000*$scale)' />
787                <xsl:variable name='y1' select='($height)+((($bottomLeftLatitude)-($fromNode/@lat))*10000*$scale*$projection)'/>
788                <xsl:text>M</xsl:text>
789                <xsl:value-of select='$x1'/>
790                <xsl:text> </xsl:text>
791                <xsl:value-of select='$y1'/>
792        </xsl:template>
793
794               
795        <!-- Generate a LineTo command for a segment start -->
796        <xsl:template name='segmentLineToStart'>
797                <xsl:variable name='from' select='@from'/>
798                <xsl:variable name='fromNode' select='key("nodeById",$from)'/>
799
800                <xsl:variable name='x1' select='($width)-((($topRightLongitude)-($fromNode/@lon))*10000*$scale)' />
801                <xsl:variable name='y1' select='($height)+((($bottomLeftLatitude)-($fromNode/@lat))*10000*$scale*$projection)'/>
802                <xsl:text>L</xsl:text>
803                <xsl:value-of select='$x1'/>
804                <xsl:text> </xsl:text>
805                <xsl:value-of select='$y1'/>
806        </xsl:template>
807
808
809        <!-- Generate a MoveTo command for a segment end -->
810        <xsl:template name='segmentMoveToEnd'>
811                <xsl:variable name='to' select='@to'/>
812                <xsl:variable name='toNode' select='key("nodeById",$to)'/>
813
814                <xsl:variable name='x2' select='($width)-((($topRightLongitude)-($toNode/@lon))*10000*$scale)'/>
815                <xsl:variable name='y2' select='($height)+((($bottomLeftLatitude)-($toNode/@lat))*10000*$scale*$projection)'/>
816                <xsl:text>M</xsl:text>
817                <xsl:value-of select='$x2'/>
818                <xsl:text> </xsl:text>
819                <xsl:value-of select='$y2'/>
820        </xsl:template>
821
822
823        <!-- Generate a LineTo command for a segment end -->
824        <xsl:template name='segmentLineToEnd'>
825                <xsl:variable name='to' select='@to'/>
826                <xsl:variable name='toNode' select='key("nodeById",$to)'/>
827
828                <xsl:variable name='x2' select='($width)-((($topRightLongitude)-($toNode/@lon))*10000*$scale)'/>
829                <xsl:variable name='y2' select='($height)+((($bottomLeftLatitude)-($toNode/@lat))*10000*$scale*$projection)'/>
830                <xsl:text>L</xsl:text>
831                <xsl:value-of select='$x2'/>
832                <xsl:text> </xsl:text>
833                <xsl:value-of select='$y2'/>
834        </xsl:template>
835       
836       
837        <!-- ============================================================================= -->
838        <!-- Drawing templates                                                             -->
839        <!-- ============================================================================= -->
840
841        <!-- Draw a line for the current <segment> element using the formatting of the current <line> instruction -->
842        <xsl:template name='drawLine'>
843                <xsl:param name='instruction'/>
844                <xsl:param name='segment'/> <!-- The current segment element -->
845                <xsl:param name='way'/>  <!-- The current way element if applicable -->
846
847                <xsl:variable name='from' select='@from'/>
848                <xsl:variable name='to' select='@to'/>
849                <xsl:variable name='fromNode' select='key("nodeById",$from)'/>
850                <xsl:variable name='toNode' select='key("nodeById",$to)'/>
851                <xsl:variable name='fromNodeContinuation' select='(count(key("segmentByFromNode",$fromNode/@id))+count(key("segmentByToNode",$fromNode/@id)))>1' />
852                <xsl:variable name='toNodeContinuation' select='(count(key("segmentByFromNode",$toNode/@id))+count(key("segmentByToNode",$toNode/@id)))>1' />
853
854                <xsl:variable name='x1' select='($width)-((($topRightLongitude)-($fromNode/@lon))*10000*$scale)' />
855                <xsl:variable name='y1' select='($height)+((($bottomLeftLatitude)-($fromNode/@lat))*10000*$scale*$projection)' />
856                <xsl:variable name='x2' select='($width)-((($topRightLongitude)-($toNode/@lon))*10000*$scale)' />
857                <xsl:variable name='y2' select='($height)+((($bottomLeftLatitude)-($toNode/@lat))*10000*$scale*$projection)' />
858
859                <!-- If this is not the end of a path then draw a stub line with a rounded linecap at the from-node end -->
860                <xsl:if test='$fromNodeContinuation'>
861                        <xsl:call-template name='drawSegmentFragment'>
862                                <xsl:with-param name='x1' select='$x1'/>
863                                <xsl:with-param name='y1' select='$y1'/>
864                                <xsl:with-param name='x2' select='number($x1)+((number($x2)-number($x1)) div 10)'/>
865                                <xsl:with-param name='y2' select='number($y1)+((number($y2)-number($y1)) div 10)'/>
866                        </xsl:call-template>
867                </xsl:if>
868
869                <!-- If this is not the end of a path then draw a stub line with a rounded linecap at the to-node end -->
870                <xsl:if test='$toNodeContinuation'>
871                        <xsl:call-template name='drawSegmentFragment'>
872                                <xsl:with-param name='x1' select='number($x2)-((number($x2)-number($x1)) div 10)'/>
873                                <xsl:with-param name='y1' select='number($y2)-((number($y2)-number($y1)) div 10)'/>
874                                <xsl:with-param name='x2' select='$x2'/>
875                                <xsl:with-param name='y2' select='$y2'/>
876                        </xsl:call-template>
877                </xsl:if>
878
879                <line>
880                        <xsl:attribute name='x1'><xsl:value-of select='$x1'/></xsl:attribute>
881                        <xsl:attribute name='y1'><xsl:value-of select='$y1'/></xsl:attribute>
882                        <xsl:attribute name='x2'><xsl:value-of select='$x2'/></xsl:attribute>
883                        <xsl:attribute name='y2'><xsl:value-of select='$y2'/></xsl:attribute>
884                        <xsl:call-template name='getSvgAttributesFromOsmTags'/>
885                </line>
886
887        </xsl:template>
888
889
890        <xsl:template name='tags'>
891                <xsl:text>"</xsl:text>
892                        <xsl:text>Segment Id = </xsl:text>
893                        <xsl:value-of select='@id'/>
894                        <xsl:text>\n</xsl:text>
895                        <xsl:text>From node = </xsl:text>
896                        <xsl:value-of select='@from'/>
897                        <xsl:text>\n</xsl:text>
898                        <xsl:text>To node = </xsl:text>
899                        <xsl:value-of select='@to'/>
900                        <xsl:text>\n</xsl:text>
901                        <xsl:for-each select='tag'>
902                                <xsl:value-of select='@k'/>
903                                <xsl:text>=</xsl:text>
904                                <xsl:value-of select='@v'/>
905                                <xsl:text>\n</xsl:text>
906                        </xsl:for-each>
907                <xsl:text>"</xsl:text>
908        </xsl:template>
909
910
911        <!-- Draw some part of a segment with round line-caps and no start or end markers -->
912        <xsl:template name='drawSegmentFragment'>
913                <xsl:param name='x1'/>
914                <xsl:param name='x2'/>
915                <xsl:param name='y1'/>
916                <xsl:param name='y2'/>
917                        <line>
918                                <xsl:attribute name='x1'><xsl:value-of select='$x1'/></xsl:attribute>
919                                <xsl:attribute name='y1'><xsl:value-of select='$y1'/></xsl:attribute>
920                                <xsl:attribute name='x2'><xsl:value-of select='$x2'/></xsl:attribute>
921                                <xsl:attribute name='y2'><xsl:value-of select='$y2'/></xsl:attribute>
922                                <!-- add the rounded linecap attribute --> 
923                                <xsl:attribute name='stroke-linecap'>round</xsl:attribute>
924                                <!-- suppress any markers else these could be drawn in the wrong place -->
925                                <xsl:attribute name='marker-start'>none</xsl:attribute>
926                                <xsl:attribute name='marker-end'>none</xsl:attribute>
927                                <xsl:call-template name='getSvgAttributesFromOsmTags'/>
928                        </line>
929        </xsl:template>
930
931
932        <!-- Draw a line for the current <way> element using the formatting of the current <line> instruction -->       
933        <xsl:template name='drawWay'>
934                <xsl:param name='instruction'/>
935                <xsl:param name='way'/>  <!-- The current way element if applicable -->
936                <xsl:param name='layer'/>
937
938                <!-- For the first and last segments in the way if the start or end is a continuation, then draw a round-capped stub segment
939                                that is 1/10th the length of the segment and without any markers.  TODO: do this for all sub-paths within the path.
940                     Count the number of segments that link to the from node of this segment.  Only count them if they belong to a way that
941                     has a layer tag that is greater than the layer of this way.  If there are any such segments then draw rounded
942                     end fragments. --> 
943                <!-- Process the first segment in the way -->
944                <xsl:variable name='firstSegment' select='key("segmentById",$way/seg[1]/@id)'/>
945                <xsl:variable name='firstSegmentFromNode' select='key("nodeById",$firstSegment/@from)'/>
946                <xsl:variable name='firstSegmentToNode' select='key("nodeById",$firstSegment/@to)'/>
947                <xsl:variable name='firstSegmentInboundLayerCount' select='count(key("wayBySegment",key("segmentByToNode",$firstSegmentFromNode/@id)/@id)/tag[@k="layer" and @v &gt;= $layer])' />
948                <xsl:variable name='firstSegmentInboundNoLayerCount' select='count(key("wayBySegment",key("segmentByToNode",$firstSegmentFromNode/@id)/@id)[count(tag[@k="layer"])=0 and $layer &lt; 1])' />
949                <xsl:variable name='firstSegmentOutboundLayerCount' select='count(key("wayBySegment",key("segmentByFromNode",$firstSegmentFromNode/@id)/@id)/tag[@k="layer" and @v &gt;= $layer])' />
950                <xsl:variable name='firstSegmentOutboundNoLayerCount' select='count(key("wayBySegment",key("segmentByFromNode",$firstSegmentFromNode/@id)/@id)[count(tag[@k="layer"])=0 and $layer &lt; 1])' />
951                <xsl:variable name='firstSegmentLayerCount' select='($firstSegmentInboundLayerCount+$firstSegmentInboundNoLayerCount+$firstSegmentOutboundLayerCount+$firstSegmentOutboundNoLayerCount)>1' />
952               
953                <xsl:if test='$firstSegmentLayerCount'>
954                        <xsl:variable name='x1' select='($width)-((($topRightLongitude)-($firstSegmentFromNode/@lon))*10000*$scale)' />
955                        <xsl:variable name='y1' select='($height)+((($bottomLeftLatitude)-($firstSegmentFromNode/@lat))*10000*$scale*$projection)' />
956                        <xsl:variable name='x2' select='($width)-((($topRightLongitude)-($firstSegmentToNode/@lon))*10000*$scale)' />
957                        <xsl:variable name='y2' select='($height)+((($bottomLeftLatitude)-($firstSegmentToNode/@lat))*10000*$scale*$projection)' />
958                        <xsl:call-template name='drawSegmentFragment'>
959                                <xsl:with-param name='x1' select='$x1'/>
960                                <xsl:with-param name='y1' select='$y1'/>
961                                <xsl:with-param name='x2' select='number($x1)+((number($x2)-number($x1)) div 10)'/>
962                                <xsl:with-param name='y2' select='number($y1)+((number($y2)-number($y1)) div 10)'/>
963                        </xsl:call-template>
964                </xsl:if>
965
966                <!-- Process the last segment in the way -->
967                <xsl:variable name='lastSegment' select='key("segmentById",$way/seg[last()]/@id)'/>
968                <xsl:variable name='lastSegmentFromNode' select='key("nodeById",$lastSegment/@from)'/>
969                <xsl:variable name='lastSegmentToNode' select='key("nodeById",$lastSegment/@to)'/>
970                <xsl:variable name='lastSegmentToNodeLayer' select='(count(key("segmentByFromNode",$lastSegmentToNode/@id)[@k="layer" and @v &gt; $layer])+count(key("segmentByToNode",$lastSegmentToNode/@id)[@k="layer" and @v &gt; $layer]))>0' />
971                <xsl:variable name='lastSegmentInboundLayerCount' select='count(key("wayBySegment",key("segmentByToNode",$lastSegmentToNode/@id)/@id)/tag[@k="layer" and @v &gt;= $layer])' />
972                <xsl:variable name='lastSegmentInboundNoLayerCount' select='count(key("wayBySegment",key("segmentByToNode",$lastSegmentToNode/@id)/@id)[count(tag[@k="layer"])=0 and $layer &lt; 1])' />
973                <xsl:variable name='lastSegmentOutboundLayerCount' select='count(key("wayBySegment",key("segmentByFromNode",$lastSegmentToNode/@id)/@id)/tag[@k="layer" and @v &gt;= $layer])' />
974                <xsl:variable name='lastSegmentOutboundNoLayerCount' select='count(key("wayBySegment",key("segmentByFromNode",$lastSegmentToNode/@id)/@id)[count(tag[@k="layer"])=0 and $layer &lt; 1])' />
975                <xsl:variable name='lastSegmentLayerCount' select='($lastSegmentInboundLayerCount+$lastSegmentInboundNoLayerCount+$lastSegmentOutboundLayerCount+$lastSegmentOutboundNoLayerCount)>1' />
976
977                <xsl:if test='$lastSegmentLayerCount'>
978                        <xsl:variable name='x1' select='($width)-((($topRightLongitude)-($lastSegmentFromNode/@lon))*10000*$scale)' />
979                        <xsl:variable name='y1' select='($height)+((($bottomLeftLatitude)-($lastSegmentFromNode/@lat))*10000*$scale*$projection)' />
980                        <xsl:variable name='x2' select='($width)-((($topRightLongitude)-($lastSegmentToNode/@lon))*10000*$scale)' />
981                        <xsl:variable name='y2' select='($height)+((($bottomLeftLatitude)-($lastSegmentToNode/@lat))*10000*$scale*$projection)' />
982                        <xsl:call-template name='drawSegmentFragment'>
983                                <xsl:with-param name='x1' select='number($x2)-((number($x2)-number($x1)) div 10)'/>
984                                <xsl:with-param name='y1' select='number($y2)-((number($y2)-number($y1)) div 10)'/>
985                                <xsl:with-param name='x2' select='$x2'/>
986                                <xsl:with-param name='y2' select='$y2'/>
987                        </xsl:call-template>
988                </xsl:if>
989
990                <!-- Now draw the way itself -->
991                <use xlink:href='#way_{$way/@id}'>
992                        <xsl:apply-templates select='$instruction/@*' mode='copyAttributes' />
993                </use>
994
995        </xsl:template>
996
997
998        <!-- Draw a circle for the current <node> element using the formatting of the current <circle> instruction -->
999        <xsl:template name='drawCircle'>
1000                <xsl:param name='instruction'/>
1001
1002                <xsl:variable name='x' select='($width)-((($topRightLongitude)-(@lon))*10000*$scale)' />
1003                <xsl:variable name='y' select='($height)+((($bottomLeftLatitude)-(@lat))*10000*$scale*$projection)'/>
1004
1005                <circle r='1' cx='{$x}' cy='{$y}'>
1006                        <xsl:apply-templates select='$instruction/@*' mode='copyAttributes' /> <!-- Copy all the svg attributes from the <circle> instruction -->               
1007                </circle>
1008               
1009        </xsl:template>
1010
1011       
1012        <!-- Draw a symbol for the current <node> element using the formatting of the current <symbol> instruction -->
1013        <xsl:template name='drawSymbol'>
1014                <xsl:param name='instruction'/>
1015
1016                <xsl:variable name='x' select='($width)-((($topRightLongitude)-(@lon))*10000*$scale)' />
1017                <xsl:variable name='y' select='($height)+((($bottomLeftLatitude)-(@lat))*10000*$scale*$projection)'/>
1018
1019                <use x='{$x}' y='{$y}'>
1020                        <xsl:apply-templates select='$instruction/@*' mode='copyAttributes'/> <!-- Copy all the attributes from the <symbol> instruction -->           
1021                </use>
1022        </xsl:template>
1023
1024
1025        <!-- Render the appropriate attribute of the current <node> element using the formatting of the current <text> instruction -->
1026        <xsl:template name='renderText'>
1027                <xsl:param name='instruction'/>
1028               
1029                <xsl:variable name='x' select='($width)-((($topRightLongitude)-(@lon))*10000*$scale)' />
1030                <xsl:variable name='y' select='($height)+((($bottomLeftLatitude)-(@lat))*10000*$scale*$projection)'/>
1031
1032                <text>
1033                        <xsl:apply-templates select='$instruction/@*' mode='copyAttributes'/>           
1034                        <xsl:attribute name='x'><xsl:value-of select='$x'/></xsl:attribute>
1035                        <xsl:attribute name='y'><xsl:value-of select='$y'/></xsl:attribute>
1036                        <xsl:call-template name='getSvgAttributesFromOsmTags'/>
1037                        <xsl:value-of select='tag[@k=$instruction/@k]/@v'/>
1038          </text>
1039        </xsl:template>
1040
1041
1042        <!-- Render the appropriate attribute of the current <segment> element using the formatting of the current <textPath> instruction -->
1043        <xsl:template name='renderTextPath'>
1044                <xsl:param name='instruction'/>
1045                <xsl:param name='pathId'/>
1046                <text>
1047                        <xsl:apply-templates select='$instruction/@*' mode='renderTextPath-text'/>
1048                        <textPath xlink:href="#{$pathId}">
1049                                <xsl:apply-templates select='$instruction/@*' mode='renderTextPath-textPath'/>
1050                                <xsl:call-template name='getSvgAttributesFromOsmTags'/>
1051                                <xsl:value-of select='tag[@k=$instruction/@k]/@v'/>
1052                        </textPath>
1053          </text>
1054        </xsl:template>
1055
1056
1057        <!-- Suppress the following attributes, allow everything else -->
1058        <xsl:template match="@startOffset|@method|@spacing|@lengthAdjust|@textLength|@k" mode='renderTextPath-text'>
1059        </xsl:template>
1060
1061        <xsl:template match="@*" mode='renderTextPath-text'>
1062                <xsl:copy/>
1063        </xsl:template>
1064
1065
1066        <!-- Allow the following attributes, suppress everything else -->
1067        <xsl:template match="@startOffset|@method|@spacing|@lengthAdjust|@textLength" mode='renderTextPath-textPath'>
1068                <xsl:copy/>
1069        </xsl:template>
1070
1071        <xsl:template match="@*" mode='renderTextPath-textPath'>
1072        </xsl:template>
1073
1074
1075        <!-- Render the appropriate attribute of the current <way> element using the formatting of the current <area> instruction -->
1076        <xsl:template name='renderArea'>
1077                <xsl:param name='instruction'/>
1078                <xsl:param name='pathId'/>
1079               
1080                <use xlink:href="#{$pathId}">
1081                        <xsl:apply-templates select='$instruction/@*' mode='copyAttributes' />
1082                </use>
1083        </xsl:template>
1084
1085
1086        <!-- Copy all attributes  -->
1087        <xsl:template match='@*' mode='copyAttributes'>
1088                <xsl:copy/>
1089        </xsl:template>
1090       
1091        <!-- If there are any tags like <tag k="svg:font-size" v="5"/> then add these as attributes of the svg output --> 
1092        <xsl:template name='getSvgAttributesFromOsmTags'>
1093                <xsl:for-each select='tag[contains(@k,"svg:")]'>
1094                        <xsl:attribute name='{substring-after(@k,"svg:")}'><xsl:value-of select='@v'/></xsl:attribute>
1095                </xsl:for-each> 
1096        </xsl:template>
1097       
1098       
1099        <!-- ============================================================================= -->
1100        <!-- Fairly static stuff                                                           -->
1101        <!-- ============================================================================= -->
1102
1103        <!-- Draw an approximate scale in the bottom left corner of the map -->
1104        <xsl:template name='scaleDraw'>
1105                <xsl:variable name='x1' select='20' />
1106                <xsl:variable name='y1' select='round(($documentHeight)+((($bottomLeftLatitude)-(number($bottomLeftLatitude)))*10000*$scale*$projection))-20'/>
1107                <xsl:variable name='x2' select='$x1+$km'/>
1108                <xsl:variable name='y2' select='$y1'/>
1109               
1110
1111                <line class='map-scale-casing'>
1112                        <xsl:attribute name='x1'><xsl:value-of select='$x1'/></xsl:attribute>
1113                        <xsl:attribute name='y1'><xsl:value-of select='$y1'/></xsl:attribute>
1114                        <xsl:attribute name='x2'><xsl:value-of select='$x2'/></xsl:attribute>
1115                        <xsl:attribute name='y2'><xsl:value-of select='$y2'/></xsl:attribute>
1116                </line>
1117               
1118                <line class='map-scale-core' stroke-dasharray='{($km div 10)}'>
1119                        <xsl:attribute name='x1'><xsl:value-of select='$x1'/></xsl:attribute>
1120                        <xsl:attribute name='y1'><xsl:value-of select='$y1'/></xsl:attribute>
1121                        <xsl:attribute name='x2'><xsl:value-of select='$x2'/></xsl:attribute>
1122                        <xsl:attribute name='y2'><xsl:value-of select='$y2'/></xsl:attribute>
1123                </line>
1124
1125                <line class='map-scale-bookend'>
1126                        <xsl:attribute name='x1'><xsl:value-of select='number($x1)'/></xsl:attribute>
1127                        <xsl:attribute name='y1'><xsl:value-of select='number($y1)+2'/></xsl:attribute>
1128                        <xsl:attribute name='x2'><xsl:value-of select='number($x1)'/></xsl:attribute>
1129                        <xsl:attribute name='y2'><xsl:value-of select='number($y1)-10'/></xsl:attribute>
1130                </line>
1131
1132                <line class='map-scale-bookend'>
1133                        <xsl:attribute name='x1'><xsl:value-of select='number($x2)'/></xsl:attribute>
1134                        <xsl:attribute name='y1'><xsl:value-of select='number($y2)+2'/></xsl:attribute>
1135                        <xsl:attribute name='x2'><xsl:value-of select='number($x2)'/></xsl:attribute>
1136                        <xsl:attribute name='y2'><xsl:value-of select='number($y2)-10'/></xsl:attribute>
1137                </line>
1138
1139                <text class='map-scale-caption'>
1140                        <xsl:attribute name='x'><xsl:value-of select='$x1'/></xsl:attribute>
1141                        <xsl:attribute name='y'><xsl:value-of select='number($y1)-10'/></xsl:attribute>
1142                        0
1143                </text>
1144
1145                <text class='map-scale-caption'>
1146                        <xsl:attribute name='x'><xsl:value-of select='$x2'/></xsl:attribute>
1147                        <xsl:attribute name='y'><xsl:value-of select='number($y2)-10'/></xsl:attribute>
1148                        1km
1149                </text>
1150
1151        </xsl:template>
1152
1153
1154        <xsl:template name='eraseOutsideBoundingBox'>
1155                <xsl:variable name='topMargin' select='(number($trlat)-number($topRightLatitude))*10000*$scale*$projection'/>
1156                <xsl:variable name='leftMargin' select='(number($bottomLeftLongitude)-number($bllon))*10000*$scale'/>
1157                <xsl:variable name='rightMargin' select='(number($trlon)-number($topRightLongitude))*10000*$scale'/>
1158                <xsl:variable name='bottomMargin' select='(number($bottomLeftLatitude)-number($bllat))*10000*$scale*$projection'/>
1159                <g fill="white" stroke="none">
1160                        <rect x='{0-$leftMargin}px' y='{0-$topMargin}px' width='{$documentWidth+$leftMargin}px' height='{$topMargin}px'/>
1161                        <rect x='{$documentWidth}px' y='{0-$topMargin}px' width='{$rightMargin}px' height='{$topMargin+$documentHeight}px'/>
1162                        <rect x='{0-$leftMargin}px' y='0px' width='{$leftMargin}px' height='{$documentHeight+$bottomMargin}px'/>
1163                        <rect x='0px' y='{$documentHeight}px' width='{$documentWidth+$rightMargin}px' height='{$bottomMargin}px'/>
1164                </g>
1165        </xsl:template>
1166
1167
1168        <!-- Draw a grid over the map in 1km increments -->
1169        <xsl:template name='gridDraw'>
1170                <xsl:call-template name='gridDrawHorizontals'>
1171                        <xsl:with-param name='line' select='"1"'/>
1172                </xsl:call-template>
1173                <xsl:call-template name='gridDrawVerticals'>
1174                        <xsl:with-param name='line' select='"1"'/>
1175                </xsl:call-template>
1176        </xsl:template>
1177       
1178        <xsl:template name='gridDrawHorizontals'>
1179                <xsl:param name='line'/>
1180                <xsl:if test='($line*$km) &lt; $documentHeight'>
1181                        <line x1='0px' y1='{$line*$km}px' x2='{$documentWidth}px' y2='{$line*$km}px' class='map-grid-line'/>
1182                        <xsl:call-template name='gridDrawHorizontals'>
1183                                <xsl:with-param name='line' select='$line+1'/>
1184                        </xsl:call-template>
1185                </xsl:if>
1186        </xsl:template>
1187
1188        <xsl:template name='gridDrawVerticals'>
1189                <xsl:param name='line'/>
1190                <xsl:if test='($line*$km) &lt; $documentWidth'>
1191                        <line x1='{$line*$km}px' y1='0px' x2='{$line*$km}px' y2='{$documentHeight}px' class='map-grid-line'/>
1192                        <xsl:call-template name='gridDrawVerticals'>
1193                                <xsl:with-param name='line' select='$line+1'/>
1194                        </xsl:call-template>
1195                </xsl:if>
1196        </xsl:template>
1197
1198
1199        <!-- Draw map border -->
1200        <xsl:template name='borderDraw'>
1201                <line x1="0" y1="0" x2="0" y2="{$documentHeight}" class='map-border-casing' stroke-dasharray="{($km div 10) - 1},1" /> <!-- dasharray can be overridden in stylesheet -->
1202                <line x1="0" y1="0" x2="{$documentWidth}" y2="0" class='map-border-casing' stroke-dasharray="{($km div 10) - 1},1" /> <!-- dasharray can be overridden in stylesheet -->
1203                <line x1="0" y1="{$documentHeight}" x2="{$documentWidth}" y2="{$documentHeight}" class='map-border-casing' stroke-dasharray="{($km div 10) - 1},1" /> <!-- dasharray can be overridden in stylesheet -->
1204                <line x1="{$documentWidth}" y1="0" x2="{$documentWidth}" y2="{$documentHeight}" class='map-border-casing' stroke-dasharray="{($km div 10) - 1},1" /> <!-- dasharray can be overridden in stylesheet -->
1205
1206                <line x1="0" y1="0" x2="0" y2="{$documentHeight}" class='map-border-core' stroke-dasharray="{($km div 10) - 1},1" /> <!-- dasharray can be overridden in stylesheet -->
1207                <line x1="0" y1="0" x2="{$documentWidth}" y2="0" class='map-border-core' stroke-dasharray="{($km div 10) - 1},1" /> <!-- dasharray can be overridden in stylesheet -->
1208                <line x1="0" y1="{$documentHeight}" x2="{$documentWidth}" y2="{$documentHeight}" class='map-border-core' stroke-dasharray="{($km div 10) - 1},1" /> <!-- dasharray can be overridden in stylesheet -->
1209                <line x1="{$documentWidth}" y1="0" x2="{$documentWidth}" y2="{$documentHeight}" class='map-border-core' stroke-dasharray="{($km div 10) - 1},1" /> <!-- dasharray can be overridden in stylesheet -->
1210        </xsl:template>
1211
1212
1213        <!-- Draw zoom controls -->
1214        <xsl:template name='zoomControl'>
1215                <defs>
1216
1217                        <style type='text/css'>
1218                          .fancyButton {
1219                            stroke: #8080ff;
1220                            stroke-width: 2px;
1221                            fill: #fefefe;
1222                            }
1223                          .fancyButton:hover {
1224                            stroke: red;
1225                            }
1226                        </style>
1227
1228                        <filter id="fancyButton" filterUnits="userSpaceOnUse" x="0" y="0" width="200" height="350">
1229                                <feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
1230                                <feOffset in="blur" dx="2" dy="2" result="offsetBlur"/>
1231                                <feSpecularLighting in="blur" surfaceScale="5" specularConstant=".75" 
1232                          specularExponent="20" lighting-color="white" 
1233                          result="specOut">
1234                                        <fePointLight x="-5000" y="-10000" z="7000"/>
1235                                </feSpecularLighting>
1236                                <feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/>
1237                                <feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" 
1238                   k1="0" k2="1" k3="1" k4="0" result="litPaint"/>
1239                                <feMerge>
1240                                        <feMergeNode in="offsetBlur"/>
1241                                        <feMergeNode in="litPaint"/>
1242                                </feMerge>
1243                        </filter>
1244                        <symbol id="panDown" viewBox="0 0 19 19" class='fancyButton'>
1245                                <path d="M 17 9.5 A 7 7 0 1 1 2,9.5 A 7 7 0 1 1 17 9.5 z" />
1246                                <path d="M 9.5,5 L 9.5,14"/>
1247                        </symbol>
1248                        <symbol id="panUp" viewBox="0 0 19 19" class='fancyButton'>
1249                                <path d="M 17 9.5 A 7 7 0 1 1 2,9.5 A 7 7 0 1 1 17 9.5 z" />
1250                                <path d="M 9.5,5 L 9.5,14"/>
1251                        </symbol>
1252                        <symbol id="panLeft" viewBox="0 0 19 19" class='fancyButton'>
1253                                <path d="M 17 9.5 A 7 7 0 1 1 2,9.5 A 7 7 0 1 1 17 9.5 z" />
1254                                <path d="M 5,9.5 L 14,9.5"/>
1255                        </symbol>
1256                        <symbol id="panRight" viewBox="0 0 19 19" class='fancyButton'>
1257                                <path d="M 17 9.5 A 7 7 0 1 1 2,9.5 A 7 7 0 1 1 17 9.5 z" />
1258                                <path d="M 5,9.5 L 14,9.5"/>
1259                        </symbol>
1260                        <symbol id="zoomIn" viewBox="0 0 19 19" class='fancyButton'>
1261                                <path d="M 17 9.5 A 7 7 0 1 1 2,9.5 A 7 7 0 1 1 17 9.5 z" />
1262                                <path d="M 5,9.5 L 14,9.5 M 9.5,5 L 9.5,14"/>
1263                        </symbol>
1264                        <symbol id="zoomOut" viewBox="0 0 19 19" class='fancyButton'>
1265                                <path d="M 17 9.5 A 7 7 0 1 1 2,9.5 A 7 7 0 1 1 17 9.5 z" />
1266                                <path d="M 5,9.5 L 14,9.5"/>
1267                        </symbol>
1268                       
1269                </defs>
1270               
1271                <g id='gPanDown' filter='url(#fancyButton)'>
1272                        <xsl:if test='/rules/@javaScript="yes"'>
1273                                <xsl:attribute name="onclick">fnPan("down")</xsl:attribute>
1274                        </xsl:if>
1275                        <use x="18px" y="60px" xlink:href="#panDown" width='14px' height='14px' />
1276                       
1277                </g>
1278                <g id='gPanRight' filter='url(#fancyButton)'>
1279                        <xsl:if test='/rules/@javaScript="yes"'>
1280                                <xsl:attribute name="onclick">fnPan("right")</xsl:attribute>
1281                        </xsl:if>
1282                        <use x="8px" y="70px" xlink:href="#panRight" width='14px' height='14px' />
1283                </g>   
1284                <g id='gPanLeft' filter='url(#fancyButton)'>
1285                        <xsl:if test='/rules/@javaScript="yes"'>
1286                                <xsl:attribute name="onclick">fnPan("left")</xsl:attribute>
1287                        </xsl:if>
1288                        <use x="28px" y="70px" xlink:href="#panLeft" width='14px' height='14px' />
1289                </g>   
1290                <g id='gPanUp' filter='url(#fancyButton)'>
1291                        <xsl:if test='/rules/@javaScript="yes"'>
1292                                <xsl:attribute name="onclick">fnPan("up")</xsl:attribute>
1293                        </xsl:if>
1294                        <use x="18px" y="80px" xlink:href="#panUp" width='14px' height='14px' />
1295                </g>   
1296
1297
1298`               <xsl:variable name='x1' select='25' />
1299                <xsl:variable name='y1' select='105'/>
1300                <xsl:variable name='x2' select='25'/>
1301                <xsl:variable name='y2' select='300'/>
1302               
1303                <line style="stroke-width: 10; stroke-linecap: butt; stroke: #8080ff;">
1304                        <xsl:attribute name='x1'><xsl:value-of select='$x1'/></xsl:attribute>
1305                        <xsl:attribute name='y1'><xsl:value-of select='$y1'/></xsl:attribute>
1306                        <xsl:attribute name='x2'><xsl:value-of select='$x2'/></xsl:attribute>
1307                        <xsl:attribute name='y2'><xsl:value-of select='$y2'/></xsl:attribute>
1308                </line>
1309               
1310                <line style="stroke-width: 8; stroke-linecap: butt; stroke: white; stroke-dasharray: 10,1;">
1311                        <xsl:attribute name='x1'><xsl:value-of select='$x1'/></xsl:attribute>
1312                        <xsl:attribute name='y1'><xsl:value-of select='$y1'/></xsl:attribute>
1313                        <xsl:attribute name='x2'><xsl:value-of select='$x2'/></xsl:attribute>
1314                        <xsl:attribute name='y2'><xsl:value-of select='$y2'/></xsl:attribute>
1315                </line>
1316
1317                       
1318                <g id='gZoomIn' filter='url(#fancyButton)' >
1319                        <xsl:if test='/rules/@javaScript="yes"'>
1320                                <!-- Need to use onmousedown because onclick is interfered with by the onmousedown handler for panning -->
1321                                <xsl:attribute name="onmousedown">fnZoom("in")</xsl:attribute>
1322                        </xsl:if>
1323                        <use x="15.5px" y="100px" xlink:href="#zoomIn" width='19px' height='19px'/>
1324                </g>
1325
1326                <g id='gZoomOut' filter='url(#fancyButton)' >
1327                        <xsl:if test='/rules/@javaScript="yes"'>
1328                                <!-- Need to use onmousedown because onclick is interfered with by the onmousedown handler for panning -->
1329                                <xsl:attribute name="onmousedown">fnZoom("out")</xsl:attribute>
1330                        </xsl:if>
1331                        <use x="15.5px" y="288px" xlink:href="#zoomOut" width='19px' height='19px' />
1332                </g>
1333        </xsl:template>
1334
1335
1336        <!-- Draw the copyright and attribution details at the top of the map -->
1337        <xsl:template name='attribution'>
1338                <g id='gAttribution'>
1339                        <a xlink:href='http://www.openstreetmap.org'>
1340                                <image 
1341                                  x="10px" 
1342                                  y="10px" 
1343                                  width="75px" 
1344                                  height="25px"
1345                                  xlink:href="Osm_linkage.png">
1346                                        <title>Copyright OpenStreetMap 2006</title>
1347                                </image>
1348                                <text font-family='Verdana' font-size='4px' fill='black' x='10' y='40'>
1349                                Copyright 2006, OpenStreetMap.org
1350                                </text>
1351                        </a> 
1352                </g>
1353        </xsl:template>
1354       
1355
1356        <!-- Draw the license details at the bottom right of the map -->
1357        <xsl:template name='license'>
1358
1359                <g id='gLicense'>
1360                        <!--Creative Commons License-->
1361                        <a xlink:href='http://creativecommons.org/licenses/by-sa/2.0/'>
1362                                <image 
1363                                  x="90px" 
1364                                  y="13px" 
1365                                  width="60px" 
1366                                  height="20px"
1367                                  xlink:href="somerights20.png">
1368                                        <title>Creative Commons - Some Rights Reserved - Attribution-ShareAlike 2.0</title>
1369                                </image>
1370                                <text font-family='Verdana' font-size='4px' fill='black' x='90px' y='40px'>
1371                                This work is licensed under a Creative
1372                                </text>
1373                                <text font-family='Verdana' font-size='4px' fill='black' x='90px' y='45px'>
1374                                Commons Attribution-ShareAlike 2.0 License.
1375                                </text>
1376                        </a>                     
1377                </g>
1378        </xsl:template>
1379       
1380       
1381        <xsl:template name='javaScript'>
1382 
1383                <script>  <![CDATA[
1384
1385                        function fnResize() {
1386                                fnResizeElement("gAttribution")
1387                                fnResizeElement("gLicense")
1388                                fnResizeElement("gZoomIn")
1389                                fnResizeElement("gZoomOut")
1390                        }
1391               
1392
1393                        function fnResizeElement(e) {
1394                                //
1395                                var oSVG,scale,currentTranslateX,currentTranslateY,oe
1396                                //
1397                                oSVG=document.rootElement
1398                                scale=1/oSVG.currentScale
1399                                currentTranslateX=oSVG.currentTranslate.x
1400                                currentTranslateY=oSVG.currentTranslate.y
1401                                oe=document.getElementById(e)
1402                                if (oe) oe.setAttributeNS(null,"transform","scale("+scale+","+scale+") translate("+(-currentTranslateX)+","+(-currentTranslateY)+")")
1403                        }
1404
1405
1406                        function fnToggleImage(osmImage) {
1407                    var xlink = 'http://www.w3.org/1999/xlink';
1408                                ogThumbnail=document.getElementById('gThumbnail')
1409                                if (ogThumbnail.getAttributeNS(null,"visibility")=="visible") fnHideImage()
1410                                else {
1411                                        ogThumbnail.setAttributeNS(null,"visibility","visible")         
1412                                        oThumbnail=document.getElementById('thumbnail')
1413                                        oThumbnail.setAttributeNS(xlink,"href",osmImage)
1414                                }
1415                        }
1416               
1417                        function fnHideImage() {
1418                                ogThumbnail=document.getElementById('gThumbnail')
1419                                ogThumbnail.setAttributeNS(null,"visibility","hidden")         
1420                        }
1421               
1422
1423                        /* The following code originally written by Jonathan Watt (http://jwatt.org/), Aug. 2005 */
1424
1425                        if (!window)
1426                        window = this;
1427
1428
1429                        function fnOnLoad(evt) {
1430                                if (!document) window.document = evt.target.ownerDocument
1431                        }
1432
1433                        /**
1434                         * Event handlers to change the current user space for the zoom and pan
1435                         * controls to make them appear to be scale invariant.
1436                         */
1437
1438
1439                        function fnOnZoom(evt) {
1440                                try {
1441                                        if (evt.newScale === undefined) throw 'bad interface'
1442                                        // update the transform list that adjusts for zoom and pan
1443                                        var tlist = document.getElementById('staticElements').transform.baseVal
1444                                        tlist.getItem(0).setScale(1/evt.newScale, 1/evt.newScale)
1445                                        tlist.getItem(1).setTranslate(-evt.newTranslate.x, -evt.newTranslate.y)
1446                                        }
1447                                catch (e) {
1448                                        // work around difficiencies in non-moz implementations (some don't
1449                                        // implement the SVGZoomEvent or SVGAnimatedTransform interfaces)
1450                                        var de = document.documentElement
1451                                        var tform = 'scale(' + 1/de.currentScale + ') ' + 'translate(' + (-de.currentTranslate.x) + ', ' + (-de.currentTranslate.y) + ')'
1452                                        document.getElementById('staticElements').setAttributeNS(null, 'transform', tform)
1453                                        }
1454                                }
1455
1456
1457                        function fnOnScroll(evt) {
1458                                var ct = document.documentElement.currentTranslate
1459                                try {
1460                                        // update the transform list that adjusts for zoom and pan
1461                                        var tlist = document.getElementById('staticElements').transform.baseVal
1462                                        tlist.getItem(1).setTranslate(-ct.x, -ct.y)
1463                                        }
1464                                catch (e) {
1465                                        // work around difficiencies in non-moz implementations (some don't
1466                                        // implement the SVGAnimatedTransform interface)
1467                                        var tform = 'scale(' + 1/document.documentElement.currentScale + ') ' + 'translate(' + (-ct.x) + ', ' + (-ct.y) + ')';
1468                                        document.getElementById('staticElements').setAttributeNS(null, 'transform', tform)
1469                                        }
1470                                }
1471
1472                        function fnZoom(type) {
1473                                var de = document.documentElement;
1474                                var oldScale = de.currentScale;
1475                                var oldTranslate = { x: de.currentTranslate.x, y: de.currentTranslate.y };
1476                                var s = 2;
1477                                if (type == 'in') {de.currentScale *= 1.5;}
1478                                if (type == 'out') {de.currentScale /= 1.4;}
1479                                // correct currentTranslate so zooming is to the center of the viewport:
1480
1481                                var vp_width, vp_height;
1482                                try {
1483                                        vp_width = de.viewport.width;
1484                                        vp_height = de.viewport.height;
1485                                }
1486                                catch (e) {
1487                                        // work around difficiency in moz ('viewport' property not implemented)
1488                                        vp_width = window.innerWidth;
1489                                        vp_height = window.innerHeight;
1490                                }
1491                                de.currentTranslate.x = vp_width/2 - ((de.currentScale/oldScale) * (vp_width/2 - oldTranslate.x));
1492                                de.currentTranslate.y = vp_height/2 - ((de.currentScale/oldScale) * (vp_height/2 - oldTranslate.y));
1493
1494                        }
1495
1496
1497                        function fnPan(type) {
1498                                var de = document.documentElement;
1499                                var ct = de.currentTranslate;
1500                                var t = 150;
1501                                if (type == 'right') ct.x += t;
1502                                if (type == 'down') ct.y += t;
1503                                if (type == 'left') ct.x -= t;
1504                                if (type == 'up') ct.y -= t;
1505                        }
1506
1507
1508                        var gCurrentX,gCurrentY
1509                        var gDeltaX,gDeltaY
1510                        var gMouseDown=false
1511                        var gCurrentTranslate=document.documentElement.currentTranslate
1512
1513                        function fnOnMouseDown(evt) {
1514                                gCurrentX=gCurrentTranslate.x
1515                                gCurrentY=gCurrentTranslate.y
1516                                gDeltaX=evt.clientX
1517                                gDeltaY=evt.clientY
1518                                gMouseDown=true
1519                                evt.target.ownerDocument.rootElement.setAttributeNS(null,"cursor","move")
1520                        }
1521
1522
1523                        function fnOnMouseUp(evt) {
1524                                gMouseDown=false
1525                                evt.target.ownerDocument.rootElement.setAttribute("cursor","default")
1526                        }
1527
1528                        function fnOnMouseMove(evt) {
1529                                var id
1530                                if (gMouseDown) {
1531                                        gCurrentTranslate.x=gCurrentX+evt.clientX-gDeltaX
1532                                        gCurrentTranslate.y=gCurrentY+evt.clientY-gDeltaY
1533                                        }
1534                        }
1535
1536                ]]>  </script> 
1537        </xsl:template>
1538
1539</xsl:stylesheet>
1540
Note: See TracBrowser for help on using the repository browser.