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

Last change on this file since 1607 was 1607, checked in by nickburch, 14 years ago

Fix for osm api now having bounds data

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