User:Ekuester/ZeigeGPXaufOSM

From OpenStreetMap Wiki
Jump to navigation Jump to search

Die folgende Beschreibung wurde nach besten Wissen erstellt, kann aber trotzdem fehlerbehaftet sein. Eine Haftung wird nicht übernommen, Verwendung auf eigene Gefahr...

Warnung: Das Programmieren mit OpenLayers kann süchtig machen (verwendet wurde Eclipse IDE for JavaScript Web Developers-Version: Helios Service Release 1).

. Vorbereitungen

Zur Vorbereitung ladet euch die gepackte Datei OpenLayers.zip herunter und entpackt sie in ein Verzeichnis eurer Wahl. Aus diesem Verzeichnis benötigt ihr die Javascript-Datei "OpenLayers.js", außerdem das Verzeichnis "img" und das Verzeichnis "theme" mit allen Unterverzeichnissen und Dateien. Aus dem Verzeichnis "examples" braucht ihr noch die Datei "marker_shadow.png". Zwei weitere Bilddateien müssen von Change the interface to browse inputfile herunter geladen werden: Die entsprechenden Links sind button_select.gif und input_boxes.gif.

. Programmordner

Alle von außerhalb benötigten Dateien sind jetzt vorhanden. Auf dem eigenen Rechner wird jetzt an gut zugänglicher Stelle ein Ordner angelegt. Nennen wir ihn einmal "ZeigeGPXaufOSM" ... In diesem Ordner landen alle Verzeichnisse und Dateien von Punkt 1, d.h. wir haben zwei Unterverzeichnisse "img" und "theme" sowie die Dateien "button_select.gif", "input_boxes.gif", "marker_shadow.png" und "OpenLayers.js". Bitte noch einen Ordner "gpx" anlegen. In diesen Ordner kommen die GPX-Dateien, die in OpenStreetMap angezeigt werden sollen. Wer will, kann sie auch im Grundordner speichern, das könnte jedoch unübersichtlich werden ... Zum guten Schluß müssen noch vier Dateien "selbst" erstellt werden.

. CSS-Datei erstellen

Kopiere folgenden Code (bitte darauf achten, auch das erste und letzte Zeichen mit zu kopieren), füge ihn mit dem Texteditor in ein neues Dokument und speichere den Text im neu angelegten Ordner unter dem Dateinamen "style.css" (ohne ""):


@CHARSET 'UTF-8';

body {
	margin: 0px;
	position: relative;
}

#map {
	border-bottom: 1px solid black;
	width: 100%;
	height: 80%;
}

#help {
	position: absolute;
	top: 3px;
	right: 3px;
	width: 160px;
	background: #fafaf5;
	border: 1px dashed red;
	padding: 4px;
	z-index: 50000;
	font-family: arial, sans-serif;
	font-size: small;
}

#help ul {
	padding-left: 1.4em;
	margin: 0px;
	margin-bottom: 1ex;
}

#help p {
	margin: 0px;
}

#tracklength {
	position: absolute;
	bottom: 12px;
	left: 96px;
	background: #fafaf5;
	border: 1px dashed red;
	padding: 2px;
	z-index: 50000;
	font-weight: bold;
}

#toolbar {
	text-align: center;
	margin-top: 8px;
	font-size: smaller;
	/* border: 1px solid red; */
	margin-left: auto;
	margin-right: auto;
}

/*** special upload form ***/
form.uplform div.fileinputs {
	position: relative;
	height: 30px;
	width: 300px;
}

form.uplform div.fakefile {
	position: absolute;
	top: 0px;
	left: 0px;
	width: 350px;
	padding: 0;
	margin: 0;
	z-index: 1;
	line-height: 90%;
}

form.example div.fakefile input {
	margin-bottom: 5px;
	margin-left: 0;
}

form.uplform input {
	background: url('input_boxes.gif') no-repeat 0 -58px;
	border: none;
	width: 241px;
	height: 20px;
	padding-left: 3px;
	padding-top: 3px;
}

form.uplform input:focus {
	background-color: transparent;
}

form.uplform input.file {
	width: 300px;
	margin: 0;
}

form.uplform input.file.hidden {
	position: relative;
	text-align: right;
	-moz-opacity: 0;
	filter: alpha(opacity :     0);
	opacity: 0;
	z-index: 2;
}

#uploadLayer {
	background: #fafafa;
	position: absolute;
	top: 140px;
	left: 10%;
	width: 80%;
	padding: 14px;
	border: 1px dashed red;
	margin-left: auto;
	margin-right: auto;
	z-index: 20000;
}

#pickFile {
	text-align: left;
}

#showFile {
	text-align: center;
	margin-bottom: 0px;
}

/* classes */
.btn {
	border: 1px solid #fa6;
	color: #655;
	font-weight: bold;
	background: #fafafa;
}

.btn:hover {
	color: #722;
	background: white;
}

.hidelayer {
	position: absolute;
	top: 0px;
	right: 0px;
	border-left: 1px dashed red;
	border-bottom: 1px dashed red;
	padding: 3px;
	margin: 0px;
}

.upldbtn {
	font-weight: bold;
	padding: 5px;
}

.error p { /* font-weight: bold; */
	
}

.error blockquote { /* border: 1px dashed red; */
	font-weight: bold;
}

.t0 {
	padding: 4px 10px 4px 10px;
	margin-left: 6px;
	border: 1px dashed red;
}

.t1 {
	padding: 4px 10px 4px 10px;
	margin-left: 6px;
	border: 1px dashed red;
}

/* formatting of links */
a[href] {
	border-width: 0px;
	border-left-width: 1px;
	border-right-width: 1px;
	border-left-style: solid;
	border-right-style: solid;
	border-color: transparent;
	text-decoration: none;
}

a:link[href] {
	color: #a80000;
}

a:visited[href] {
	color: #aa4444;
}

a:active[href] {
	color: #ff6666;
	text-decoration: underline;
}

a:hover[href] {
	border-color: #a80000;
}

/* added for MousePosition control */
.olControlMousePosition {
	position: absolute;
	right: 10px;
	top: 0px;
	height: 15px;
	font-size: 8pt;
	background-color: white
}

#utm_mouse {
	top: 15px;
}

/* added for tooltip popup */
.popup {
	position: absolute;
	padding: 5px;
	font-size: 8pt;
	font-family: arial, sans-serif;
	z-index: 800;
	background-color: white
}

/* added for zoom control */
.olControlZoomlevel {
	position: absolute;
	left: 10px;
	bottom: 2.5em;
	height: 15px;
	font-family: arial, sans-serif;
	font-size: 10pt;
	background-color: white;
}

/* added for help panel */
div.olControlPanel {
	top: 0px;
	left: 56px;
	position: absolute;
}

.olControlPanel div {
	display: block;
	width: 22px;
	height: 24px;
	border: thin solid black;
	margin-top: 10px;
	background-color: blue
}

.helpButtonItemInactive {
	background-image: url('img/help.png');
}

/* added for edit panel */
.olToolBar {
	top: 100px;
	left: 50px;
	position: absolute;
}

.olToolBar div {
	display: block;
	width: 24px;
	height: 24px;
	margin: 5px;
	background-color: white;
	border: thin solid black;
}

.olToolBar .olControlNavigationItemActive {
	background-color: blue;
	background-image: url("theme/default/img/pan_on.png");
}

.olToolBar .olControlNavigationItemInactive {
	background-color: orange;
	background-image: url("theme/default/img/pan_off.png");
}

.olToolBar .olControlSaveFeatureItemActive {
	width: 22px;
	height: 22px;
	background-color: blue;
	background-image: url("theme/default/img/save_features_on.png");
}

.olToolBar .olControlSaveFeatureItemInactive {
	width: 22px;
	height: 22px;
	background-color: orange;
	background-image: url("theme/default/img/save_features_off.png");
}

.olToolBar .olControlDeleteFeatureItemActive {
	width: 22px;
	height: 22px;
	background-color: blue;
	background-image: url("theme/default/img/remove_point_on.png");
}

.olToolBar .olControlDeleteFeatureItemInactive {
	width: 22px;
	height: 22px;
	background-color: orange;
	background-image: url("theme/default/img/remove_point_off.png");
}

.olToolBar .olControlModifyFeatureItemActive {
	width: 22px;
	height: 22px;
	background-color: blue;
	background-image: url("theme/default/img/draw_point_on.png");
}

.olToolBar .olControlModifyFeatureItemInactive {
	width: 22px;
	height: 22px;
	background-color: orange;
	background-image: url("theme/default/img/draw_point_off.png");
}

.olToolBar .olControlDrawFeatureLineItemActive {
	width: 22px;
	height: 22px;
	background-color: blue;
	background-image: url("theme/default/img/draw_line_on.png");
}

.olToolBar .olControlDrawFeatureLineItemInactive {
	width: 22px;
	height: 22px;
	background-color: orange;
	background-image: url("theme/default/img/draw_line_off.png");
}

.olToolBar .olControlDrawFeaturePointItemActive {
	width: 22px;
	height: 22px;
	background-color: blue;
	background-image: url("theme/default/img/draw_point_on.png");
}

.olToolBar .olControlDrawFeaturePointItemInactive {
	width: 22px;
	height: 22px;
	background-color: orange;
	background-image: url("theme/default/img/draw_point_off.png");
}

.olToolBar .olControlSplitItemActive {
	width: 22px;
	height: 22px;
	background-color: blue;
}

.olToolBar .olControlSplitItemInactive {
	width: 22px;
	height: 22px;
	background-color: orange;
}

. JavaScript-Dateien erstellen

ZeigeGPX.js

Kopiere folgenden Code (bitte darauf achten, auch das erste und letzte Zeichen mit zu kopieren), füge ihn mit dem Texteditor in ein neues Dokument und speichere den Text im neu angelegten Ordner unter dem Dateinamen "ZeigeGPX.js" (ohne ""):

/**
 * GPX Datei oeffnen und in Layer anzeigen
 */
var centerPoint = null, center_style, marker_style, modify;
var selectControl = null;
var totalDistance = 0.0;

var SHADOW_Z_INDEX = 10;
var MARKER_Z_INDEX = 11;

function loadGPX() {
	var gpxfile = document.getElementById('gpxfile').value;
	if (!gpxfile) return;
	var lindx = gpxfile.lastIndexOf('\\');
	if (lindx == 0) lindx = gpxfile.lastIndexOf('/');
	if (lindx == 0) return;
	url = path + gpxfile.substr(lindx+1);
	document.getElementById('routename').value = url;
	hideLayer("uploadLayer");
	OpenLayers.loadURL(url, null, null, requestSuccess, requestFailure);
}

/*
 * function: requestSuccess
 * Process XML file after it has been loaded.
 *
 * Parameters:
 * request - {String} 
 */
function requestSuccess(request) {
	var doc = request.responseText;
	if (!typeof(doc) == "string") {
		requestFailure(request);
	}
	// order for collecting features 1. tracks 2. routes 3. waypoints
	gpx =  new OpenLayers.Format.GPX({
		extractAttributes: true,
		extractStyles: false,
		extractTracks: true, // as LineStrings
		extractRoutes: true, // as LineStrings
		extractWaypoints: true, // as Points
		externalProjection : map.displayProjection, // WGS84
		internalProjection : map.projection // Merkator
	});
	// styles for waypoints
	marker_style = OpenLayers.Util.applyDefaults({
		'cursor': 'pointer',
		'externalGraphic': 'img/marker-blue.png',
		'graphicHeight': 25,
		'graphicWidth': 21,
		'graphicOpacity': 0.8,
		'graphicXOffset': -10.5,
		'graphicYOffset': -25,
        'graphicZIndex': MARKER_Z_INDEX,
        'backgroundGraphicZIndex': SHADOW_Z_INDEX
	},OpenLayers.Feature.Vector.style['default']);
	center_style = OpenLayers.Util.applyDefaults({
		'cursor': 'pointer',
        // set the external graphic and background graphic images.
		'externalGraphic': 'img/marker-gold.png',
        'backgroundGraphic': 'marker_shadow.png',
		'fontFamily': 'arial, sans-serif',
		'fontSize': '10pt',
		'graphicHeight': 25,
		'graphicWidth': 21,
		'graphicOpacity': 0.8,
		'graphicXOffset': -10.5,
		'graphicYOffset': -25,
        // makes sure the background graphic is placed correctly relative
        // to the external graphic.
        'backgroundXOffset': 0,
        'backgroundYOffset': -25,
        // Set the z-indexes of both graphics to make sure the background
        // graphics stay in the background (shadows on top of markers looks odd
        'graphicZIndex': MARKER_Z_INDEX,
        'backgroundGraphicZIndex': SHADOW_Z_INDEX,
	    'label': 'Infos',
	    'pointRadius': 10
	},OpenLayers.Feature.Vector.style['default']);
	// style for tracks and track vertices
    var styles = new OpenLayers.StyleMap({
        "default": new OpenLayers.Style(null, {
            rules: [
                new OpenLayers.Rule({
                    symbolizer: {
                        "Point": {
                    		cursor: 'pointer',
                            fillColor: 'white',
                            fillOpacity: 0.25,
                            pointRadius: 4,
                            graphicName: 'triangle', // ÒcircleÓ(default), ÒsquareÓ, ÒstarÓ, ÒxÓ, ÒcrossÓ, "triangle"
                            strokeWidth: 1,
                            strokeOpacity: 1,
                            strokeColor: "#333333"
                        },
                        "Line": {
                    		cursor: 'pointer',
                            strokeWidth: 3,
                            strokeOpacity: 1,
                            strokeColor: '#666666'
                        }
                    }
                })
            ]
        }),
        "select": new OpenLayers.Style({
            strokeColor: "#00ccff", // light blue
            strokeWidth: 3
        }),
        "temporary": new OpenLayers.Style(null, {
            rules: [
                new OpenLayers.Rule({
                    symbolizer: {
                        "Point": {
                    		cursor: 'pointer',
                            fillColor: 'white',
                            fillOpacity: 0.25,
                            pointRadius: 4,
                            graphicName: 'triangle',
                            strokeWidth: 1,
                            strokeOpacity: 1,
                            strokeColor: '#333333'
                        },
                        "Line": {
                    		cursor: 'pointer',
                            strokeWidth: 3,
                            strokeOpacity: 1,
                            strokeColor: '#00ccff' // light blue
                        }
                    }
                })
            ]
        })
    });
    var gpxLayer = new OpenLayers.Layer.Vector("Strecke / Wegpunkte", {
        eventListeners: {
            "featureadded": onFeatureAdded
        },
    	projection: map.displayProjection,
    	styleMap: styles
    });
    // read the feature vectors, all points in m from Merkator projection
    features = gpx.read(doc);
    gpxLayer.addFeatures(features);
    var bounds = gpxLayer.getDataExtent();
    lonLat = bounds.getCenterLonLat();
    // mark the center
    map.setCenter(lonLat);
    // fit zoom to bounds if desired
    map.zoomToExtent(bounds);
    zoom = map.getZoom();
    centerPoint = new OpenLayers.Feature.Vector(new
    		OpenLayers.Geometry.Point(lonLat.lon, lonLat.lat), {
    	'name': 'Streckenmitte',
    	'wegstrecke': totalDistance.toFixed(3)+' km',
    	'zoomstufe': zoom
    }, center_style);
    map.events.register('zoomend', centerPoint, displayAfterZoom);
    gpxLayer.addFeatures([centerPoint]);
    map.addLayer(gpxLayer);
    // panels seem not to work with K-meleon under Windows
    // add some editing tools to a panel
    var panel = new OpenLayers.Control.Panel(
    		{displayClass: 'olToolBar'});
    var navigate = new OpenLayers.Control.Navigation({title: 'Verschieben/Zoomen'});
    var draw = new OpenLayers.Control.DrawFeature(
    		gpxLayer, OpenLayers.Handler.Path,
    		{
    			featureAdded: onFeatureAdded,
    			title: "Linie zeichnen",
    			displayClass: "olControlDrawFeatureLine",
    			handlerOptions: {multi: false}
    		});
    modify = new OpenLayers.Control.ModifyFeature(
    		gpxLayer, {displayClass: "olControlModifyFeature", title: "Umzeichnen"});
    var del = new DeleteFeature(gpxLayer, {title: "Punkt/Linie entfernen"});
    var save = new OpenLayers.Control.Button({
    	title: "Abspeichern",
    	trigger: function() {
    		if(modify.feature) {
    			alert("unselect");
    			modify.selectControl.unselectAll();
    		}
    		//saveStrategy.save();
    		alert("Speichern geht noch nicht");
    	},
    	displayClass: "olControlSaveFeature"
    });
    panel.addControls([navigate, save, del, modify, draw]);
    panel.defaultControl = panel.controls[0];
	map.addControl(panel);
	// style for SelectFeature control
	control_selectStyle = {
    		'externalGraphic': 'img/marker-blue.png',
    		'graphicHeight': 25,
    		'graphicWidth': 21,
    		'graphicOpacity': 0.3,
    		'graphicXOffset': -10.5,
    		'graphicYOffset': -25,
    		'strokeWidth': 3,
    		'strokeColor': '#00ccff' // light blue
    };
	// Add a SelectFeature control for tooltip creation
    var layers = map.getLayersByClass('OpenLayers.Layer.Vector');
    selectControl = new OpenLayers.Control.SelectFeature(layers, {
    	callbacks : {
    		over: featureOver,
    		out: function(feature) {
    			hideTooltip();
    			this.unhighlight(feature);
    		}
    	},
    	selectStyle: control_selectStyle
    });
    map.addControl(selectControl);
    selectControl.activate();
    // register multiple listeners to be called with the same `this` object
    gpxLayer.events.on({
    	'featuremodified': onFeatureModified,
    	'beforefeatureremoved': beforeFeatureRemoved,
    	scope: centerPoint
    });
}

/**
 * function: requestFailure
 * Process a failed loading of XML file.
 *
 * Parameters:
 * request - {String} 
 */
function requestFailure(request) {
	alert("Fehlschlag: "+this.url);
	this.events.triggerEvent("loadend");
}

DeleteFeature = OpenLayers.Class(OpenLayers.Control, {
	initialize: function(layer, options) {
		OpenLayers.Control.prototype.initialize.apply(this, [options]);
		this.layer = layer;
		this.handler = new OpenLayers.Handler.Feature(
				this, layer, {click: this.clickFeature}
		);
	},
	clickFeature: function(feature) {
		if (feature != centerPoint) {
	    	// remove feature only if not center point
	        feature.renderIntent = "select";
	        this.layer.drawFeature(feature);
			form = (feature.geometry.CLASS_NAME == 'OpenLayers.Geometry.Point') ? 'Punkt': 'Linie';
		    Check = confirm(form+" wirklich entfernen?");
		    if (Check) {
		    	this.layer.removeFeatures([feature]);
		    	hideTooltip();
		    }
		    else {
		        feature.renderIntent = "default";
		        this.layer.drawFeature(feature);		    	
		    }
		}
	},
	setMap: function(map) {
		this.handler.setMap(map);
		OpenLayers.Control.prototype.setMap.apply(this, arguments);
	},
	CLASS_NAME: "OpenLayers.Control.DeleteFeature"
});

/*
 * Openlayers.Layer.Vector has added the features
 */
function onFeatureAdded(event) {
	// 'this' is layer
	feature = event.feature;
	if (feature.geometry.CLASS_NAME == 'OpenLayers.Geometry.LineString') {
		// calculate and store the distance of the track
		actualDistance = feature.geometry.getGeodesicLength(map.projection)/1000;			
		// round to 3 significant digits
		feature.attributes['distance'] = actualDistance.toFixed(3);
		totalDistance += actualDistance;
		if (centerPoint != null)
			centerPoint.attributes['wegstrecke'] = totalDistance.toFixed(3)+' km';

	}
	else {
		// set the style for waypoints
		if (feature != centerPoint)
			feature.style = marker_style;			
	}
	OpenLayers.Event.stop(event);	
}

function onFeatureModified(event) {
	// 'this' is the centerPoint feature
	feature = event.feature;
	if (feature.geometry.CLASS_NAME == 'OpenLayers.Geometry.LineString') {
		// update track and total distance
		var lastDistance = parseFloat(feature.attributes['distance']);
		totalDistance -= lastDistance;
		var actualDistance = feature.geometry.getGeodesicLength(map.projection)/1000;
		totalDistance += actualDistance;
		feature.attributes['distance'] = actualDistance.toFixed(3);
		this.attributes['wegstrecke'] = totalDistance.toFixed(3)+' km';
	}
	OpenLayers.Event.stop(event);	
}

/*
 * Openlayers.Layer.Vector has removed a feature
 */
function beforeFeatureRemoved(event) {
	// 'this' is centerPoint feature
    feature = event.feature;
	if (feature.geometry.CLASS_NAME == 'OpenLayers.Geometry.LineString') {
		// decrease the total Distance by length of track
		var lastDistance = parseFloat(feature.attributes['distance']);			
		totalDistance -= lastDistance;
		centerPoint.attributes['wegstrecke'] = totalDistance.toFixed(3)+' km';
	}
	OpenLayers.Event.stop(event);	
}

function getHTMLCode(feature) {
	if (feature.geometry.CLASS_NAME == 'OpenLayers.Geometry.LineString') {
		// popup for track
		var distance = feature.attributes.distance;
		var popupContentHTML = '<p>Streckenabschnitt<br>Länge: '+distance+' km<br>klicken zum Markieren!</p><div style="clear:both;"></div>';
	}
	else {
		// popup for waypoint
		var sAttributes = '<p>Wegpunkt<br>';
		for ( var key in feature.attributes ) {
			var schluessel;
			var wert = feature.attributes[key];
			switch (key) {
			case 'ele':
				schluessel = 'höhe';
				wert += ' m';
				break;
			case 'time':
				schluessel = 'zeit';
				break;
			default:
				schluessel = key;
			break;
			}

			sAttributes = sAttributes+'• '+OpenLayers.String.camelize('-'+schluessel)+': '+wert+'<br>';
		}
		sAttributes += '</p><div style="clear:both;"></div>';
		var popupContentHTML = sAttributes;
	}
	return popupContentHTML;
}

function displayAfterZoom(event) {
	// this is the centerPoint feature
	zoom = this.layer.map.getZoom();
	this.attributes.zoomstufe = zoom;
	OpenLayers.Event.stop(event);	
}

function featureOver(feature) {
	// 'this' is selectFeature control
	this.highlight(feature);
	if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") {
		// calculate and store the distance of every track
		var actualDistance = feature.geometry.getGeodesicLength(map.projection)/1000;			
		// round to 3 significant digits
		feature.attributes['distance'] = actualDistance.toFixed(3);
	}
	var xy = this.map.getControl('leftMouseXy').lastXy || new OpenLayers.Pixel(0,0);
	showTooltip(getHTMLCode(feature), xy.x, xy.y);
}

//non OpenLayers related functions
function getViewport() {
	var e = window, a = 'inner';
	if (!('innerWidth' in window)) {
		a = 'client';
		e = document.documentElement || document.body;
	}
	return {
		width : e[a + 'Width'],
		height : e[a + 'Height']
	};
}

function showTooltip(ttText, x, y) {
	var windowWidth = getViewport().width;
	var o = document.getElementById('tooltip');
	o.innerHTML = ttText;
	if (o.offsetWidth) {
		var ew = o.offsetWidth;
	} else if (o.clip.width) {
		var ew = o.clip.width;
	}
	y = y + 16;
	x = x - (ew / 4);
	if (x < 2) {
		x = 2;
	} else if (x + ew > windowWidth) {
		x = windowWidth - ew - 4;
	}
	o.style.left = x + 'px';
	o.style.top = y + 'px';
	o.style.visibility = 'visible';
}

function hideTooltip() {
	document.getElementById('tooltip').style.visibility = 'hidden';
}

OpenStreetMap.js

Kopiere folgenden Code (bitte darauf achten, auch das erste und letzte Zeichen mit zu kopieren), füge ihn mit dem Texteditor in ein neues Dokument und speichere den Text im neu angelegten Ordner unter dem Dateinamen "OpenStreetMap.js" (ohne ""):


/**
 * Namespace: Util.OSM
 */
OpenLayers.Util.OSM = {};

/**
 * Constant: MISSING_TILE_URL {String} URL of image to display for missing tiles
 */

OpenLayers.Util.OSM.MISSING_TILE_URL = "http://openstreetmap.org/openlayers/img/404.png";

/**
 * Property: originalOnImageLoadError
 * {Function} Original onImageLoadError function.
 */
OpenLayers.Util.OSM.originalOnImageLoadError = OpenLayers.Util.onImageLoadError;

/**
 * Function: onImageLoadError
 */
OpenLayers.Util.onImageLoadError = function() {
	if (this.src.match(/^http:\/\/[abc]\.[a-z]+\.openstreetmap\.org\//)) {
		this.src = OpenLayers.Util.OSM.MISSING_TILE_URL;
	} else if (this.src.match(/^http:\/\/[def]\.tah\.openstreetmap\.org\//)) {
		// do nothing - this layer is transparent
	} else {
		OpenLayers.Util.OSM.originalOnImageLoadError;
	}
};

/**
 * Class: OpenLayers.Layer.OSM.Mapnik
 *
 * Inherits from:
 *  - <OpenLayers.Layer.OSM>
 */
OpenLayers.Layer.OSM.Mapnik = OpenLayers.Class(OpenLayers.Layer.OSM, {
	/**
	 * Constructor: OpenLayers.Layer.OSM.Mapnik
	 *
	 * Parameters:
	 * name - {String}
	 * options - {Object} Hashtable of extra options to tag onto the layer
	 */
	initialize : function(name, options) {
		var url = [ "http://a.tile.openstreetmap.org/${z}/${x}/${y}.png",
				"http://b.tile.openstreetmap.org/${z}/${x}/${y}.png",
				"http://c.tile.openstreetmap.org/${z}/${x}/${y}.png" ];
		options = OpenLayers.Util.extend({
			numZoomLevels : 19
		}, options);
		var newArguments = [ name, url, options ];
		OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
	},

	CLASS_NAME : "OpenLayers.Layer.OSM.Mapnik"
});

/**
 * Class: OpenLayers.Layer.OSM.Osmarender
 *
 * Inherits from:
 *  - <OpenLayers.Layer.OSM>
 */
OpenLayers.Layer.OSM.Osmarender = OpenLayers.Class(OpenLayers.Layer.OSM, {
	/**
	 * Constructor: OpenLayers.Layer.OSM.Osmarender
	 *
	 * Parameters:
	 * options - {Object} Hashtable of extra options to tag onto the layer
	 */
	initialize : function(name, options) {
	    var url = [	"http://a.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png",
				"http://b.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png",
				"http://c.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png" ];
		options = OpenLayers.Util.extend({
			numZoomLevels : 18
		}, options);
		var newArguments = [ name, url, options ];
		OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
	},

	CLASS_NAME : "OpenLayers.Layer.OSM.Osmarender"
});

/**
 * Class: OpenLayers.Layer.OSM.CycleMap
 *
 * Inherits from:
 *  - <OpenLayers.Layer.OSM>
 */
OpenLayers.Layer.OSM.CycleMap = OpenLayers.Class(OpenLayers.Layer.OSM, {
	/**
	 * Constructor: OpenLayers.Layer.OSM.CycleMap
	 *
	 * Parameters:
	 * name - {String}
	 * options - {Object} Hashtable of extra options to tag onto the layer
	 */
	initialize : function(name, options) {
		var url = [ "http://a.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png",
				"http://b.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png",
				"http://c.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png" ];
		options = OpenLayers.Util.extend({
			numZoomLevels : 19
		}, options);
		var newArguments = [ name, url, options ];
		OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
	},

	CLASS_NAME : "OpenLayers.Layer.OSM.CycleMap"
});

/**
 * Class: OpenLayers.Layer.OSM.Maplint
 *
 * Inherits from:
 *  - <OpenLayers.Layer.OSM>
 */
OpenLayers.Layer.OSM.Maplint = OpenLayers.Class(OpenLayers.Layer.OSM, {
	/**
	 * Constructor: OpenLayers.Layer.OSM.Maplint
	 *
	 * Parameters:
	 * name - {String}
	 * options - {Object} Hashtable of extra options to tag onto the layer
	 */
	initialize : function(name, options) {
		var url = [	"http://d.tah.openstreetmap.org/Tiles/maplint/${z}/${x}/${y}.png",
				"http://e.tah.openstreetmap.org/Tiles/maplint/${z}/${x}/${y}.png",
				"http://f.tah.openstreetmap.org/Tiles/maplint/${z}/${x}/${y}.png" ];
		options = OpenLayers.Util.extend({
			numZoomLevels : 18,
			isBaseLayer : false,
			visibility : false
		}, options);
		var newArguments = [ name, url, options ];
		OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
	},

	CLASS_NAME : "OpenLayers.Layer.OSM.Maplint"
});

. HTML-Datei erstellen

Kopiere folgenden Code (bitte darauf achten, auch das erste und letzte Zeichen mit zu kopieren), füge ihn mit dem Texteditor in ein neues Dokument und speichere den Text im neu angelegten Ordner unter dem Dateinamen "ZeigeGPXaufOSM.htm" (ohne ""):

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Zeige GPX auf OSM</title>

<link rel="stylesheet" href="theme/default/style.css" type="text/css">
<link rel="stylesheet" href="style.css" type="text/css">
<!-- siehe http://code.google.com/intl/de-DE/apis/maps/terms.html -->
<script
  src="http://maps.google.com/maps?file=api&v=2&key=API_Schluessel_hier_einfuegen"
	type="text/javascript"></script>
<script src="OpenLayers.js"></script>
<script src="OpenStreetMap.js"></script>
<script src="ZeigeGPX.js"></script>
<script type="text/javascript">
    // Voreingestellte Anfangsposition fuer die Mitte der Karte
    // Standort: Krefeld
    var lon = 6.5592502; // longitude
    var lat = 51.3340369; // latitude
    var lonLat; // variable for Merkartor coordinates
    var map; // complex object of type OpenLayers.Map
    var options; // options of the map
    var path = "gpx/"; // preset for directory path
    var scriptpath;
    var zoom = 12; // // zoom level for the map

	//Initialize the 'map' object
	function init() {
	    options = {
			controls : [
			        new OpenLayers.Control.Permalink(),
					new OpenLayers.Control.Navigation(),
					new OpenLayers.Control.KeyboardDefaults(),
					new OpenLayers.Control.PanZoomBar(),
					new OpenLayers.Control.Scale(),
					new OpenLayers.Control.ScaleLine({ geodesic : true }),
					// mouse position upper right corner
					new OpenLayers.Control.MousePosition({
						id : 'leftMouseXy'
					}),
					new OpenLayers.Control.LayerSwitcher({'asscending':true}),
					new OpenLayers.Control.Attribution() ],
					//new OpenLayers.Control.KeyboardDefaults() ],
			maxExtent : new OpenLayers.Bounds(-20037508.34, -20037508.34,
					20037508.34, 20037508.34),
			maxResolution : 156543.0399,
			numZoomLevels : 19,
			units : 'm',
			projection : new OpenLayers.Projection("EPSG:900913"),
			displayProjection : new OpenLayers.Projection("EPSG:4326")
		};
		map = new OpenLayers.Map("map", options);
        // osm defined layers
		layerMapnik = new OpenLayers.Layer.OSM.Mapnik("Mapnik");
		map.addLayer(layerMapnik);
        layerOsmarender = new OpenLayers.Layer.OSM.Osmarender("Osmarender");
        map.addLayer(layerOsmarender); 
		layerCycleMap = new OpenLayers.Layer.OSM.CycleMap("CycleMap");
		map.addLayer(layerCycleMap);

		// customer defined layers

		// Oeffentlicher Nahverkehr
		//var OepnvLayer = new OpenLayers.Layer.OSM("Oepnv", "file:///D:/Tiles/Oepnv/${z}/${x}/${y}.png", {numZoomLevels: 16, alpha: true, isBaseLayer: true, visibility: false});
		var OepnvLayer = new OpenLayers.Layer.OSM("ÖPNV Karte",
				"http://tile.xn--pnvkarte-m4a.de/tilegen/${z}/${x}/${y}.png", {
					numZoomLevels : 16,
					alpha : true,
					isBaseLayer : true,
					visibility : false
				});
		map.addLayer(OepnvLayer);

		// Google Earth (dazu muss oben ein API Schluesselwert eingegeben werden)
		var layerGoogleSat = new OpenLayers.Layer.Google("Google Sat", {
			type : G_SATELLITE_MAP,
			'sphericalMercator' : true,
			numZoomLevels : 19
		});
		map.addLayer(layerGoogleSat);
/*		Google Strassenkarte
		var layerGoogleStreets = new OpenLayers.Layer.Google("Google Streets", {
		    type : G_NORMAL_MAP,
			'sphericalMercator' : true,
			numZoomLevels : 19
		});
		map.addLayer(layerGoogleStreets);
*/
		// Transparente Layer
/*	    var BahnLayer = new OpenLayers.Layer.OSM("Bahn",
				"file:///D:/Tiles/Bahn/${z}/${x}/${y}.png", {
					numZoomLevels : 17,
					alpha : true,
					isBaseLayer : false,
					visibility : false
				});
		map.addLayer(BahnLayer);
		var RadLayer = new OpenLayers.Layer.OSM("Rad",
				"file:///D:/Tiles/Rad/${z}/${x}/${y}.png", {
					numZoomLevels : 16,
					alpha : true,
					isBaseLayer : false,
					visibility : false
				});
		map.addLayer(RadLayer);

	    var WanderLayer = new OpenLayers.Layer.OSM("Wandern",
				"file:///D:/Tiles/lonvia/${z}/${x}/${y}.png", {
					numZoomLevels : 16,
					alpha : true,
					isBaseLayer : false,
					visibility : false
				});
*/
		var WanderLayer = new OpenLayers.Layer.OSM("Lonvias Wanderwege",
				"http://osm.lonvia.de/hiking/${z}/${x}/${y}.png", {
					numZoomLevels : 16,
					alpha : true,
					isBaseLayer : false,
					visibility : false
				});
		map.addLayer(WanderLayer);
		var trails = new OpenLayers.Layer.OSM('Nops Wanderwege',
				'http://wanderreitkarte.de/topo/${z}/${x}/${y}.png', {
					numZoomLevels : 16,
					alpha : true,
					isBaseLayer : false,
					visibility : false
				});
		map.addLayer(trails);

		// Hochspannungsleitungen
/*		var StromLayer = new OpenLayers.Layer.OSM("Strom",
				"file:///D:/Tiles/Power/${z}/${x}/${y}.png", {
					numZoomLevels : 17,
					alpha : true,
					isBaseLayer : false,
					visibility : false
				}); */
		var StromLayer = new OpenLayers.Layer.OSM("OSM Power",
				"http://bahnradwandern.bplaced.net/power/${z}/${x}/${y}.png", {
					numZoomLevels : 16,
					alpha : true,
					isBaseLayer : false,
					visibility : false
				});
		map.addLayer(StromLayer);

		var lindx = document.URL.lastIndexOf('/') + 1;
		scriptpath = document.URL.slice(0, lindx);
		document.getElementById('path').value = scriptpath;
		var switcherControl = new OpenLayers.Control.LayerSwitcher();
		map.addControl(switcherControl);
		switcherControl.maximizeControl();
		lonLat = new OpenLayers.LonLat(lon, lat).transform(
				new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
		if (!map.getCenter()) {
			map.setCenter(new OpenLayers.LonLat(0, 0), 0);
			map.zoomToMaxExtent();
		}
		map.setCenter(lonLat, zoom);
}

function deleteVectorLayer() {
	var controls = map.getControlsByClass('OpenLayers.Control.Panel');
    var layers = map.getLayersByClass('OpenLayers.Layer.Vector');
    for (var num in layers) {
    	map.removeControl(controls[num]);
    	var layer = layers[num];
    	map.removeLayer(layer, true);
    	layer.destroyFeatures();
    	layer.destroy();
    }
    totalDistance = 0.0;
}

/************************************************************************ 
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 (C) 2008 Harald Kirsch <http://www.pifpafpuf.de> (pifpafpuf at gmx dot de)
**************************************************************************/

function toggleLayer(id, dstyle) {
	  e = document.getElementById(id);
	  if( e.style.display=='none' ) showLayer(id, dstyle);
	  else hideLayer(id);
}

function showLayer(id, dstyle) {
	  e = document.getElementById(id);
	  e.style.display = dstyle;
	}
	function hideLayer(id) {
	  e = document.getElementById(id);
	  e.style.display = "none";
	}

	function setCursor(id, cursor) {
	  var e = document.getElementById(id);
	  e.style.cursor = cursor;
}

function mapFullsize() {
  var maph = window.innerHeight - 100;
  document.getElementById('map').style.height = "" + maph + "px";
}

function sizeMap(deltaPx) {
  var e = document.getElementById('map');
  var h = e.style.height;
  if (h == '')
	h = window.getComputedStyle(e, null).height;
	var height = parseInt(h) + deltaPx;
	if (height < 100)
	  return;
	e.style.height = "" + height + 'px';
	map.updateSize();
}
	
/*
 * prepare file select button
 * code by Peter-Paul Koch
 * website: http://www.quirksmode.org/dom/inputfile.html
 * needed images input_boxes.gif und button_select.gif are on
 * website: http://css3c.com/css2/change-the-interface-to-browse-input-file/
 */
var W3CDOM = (document.createElement && document.getElementsByTagName);

function initFileUploads() {
  if (!W3CDOM) return;
  var fakeFileUpload = document.createElement('div');
  fakeFileUpload.className = 'fakefile';
  fakeFileUpload.appendChild(document.createElement('input'));
  var image = document.createElement('img');
  image.src='button_select.gif';
  fakeFileUpload.appendChild(image);
  var x = document.getElementsByTagName('input');
  for (var i=0;i<x.length;i++) {
    if (x[i].type != 'file') continue;
    if (x[i].parentNode.className != 'fileinputs') continue;
    x[i].className = 'file hidden';
    var clone = fakeFileUpload.cloneNode(true);
    x[i].parentNode.appendChild(clone);
    x[i].relatedElement = clone.getElementsByTagName('input')[0];
    //x[i].onchange = x[i].onmouseout = function () {
    x[i].onmouseout = function () {
      this.relatedElement.value = this.value;
    }
  }
}
</script>

</head>
<!-- contributors: Harald Kirsch, Sven Geggus, Andre Joost, Erich Kuester -->
<!-- body.onload is invoked once the page is loaded (and calls the init functions) -->
<body onload="init(); initFileUploads();">
<!-- define a DIV into which the map will appear. Make it take up the whole window -->
<div id="map"><!-- see style.css for dimensions --></div>
<!-- tooltip popup -->
<div class="popup" id="tooltip" style="visibility: hidden"></div>
<!-- help page -->
<div id='help' style='display:none'>
<p id='warnEmpty' style='display: none; color: red'>
Noch keine Punkte gespeichert, bitte erst
Punkte setzen, dann auf 'speichern' klicken, um den Track und die Wegpunkte zu sehen
</p>
<p><b>Hilfe für die fünf Schaltflächen links:</b><br>
(vorher Datei einladen und anzeigen lassen)</p>
<ul>
	<li>auf Navigieren schalten</li>
	<li>Abspeichern</li>
	<li>Punkt/Linie löschen</li>
	<li>Linienverlauf ändern</li>
	<li>Neue Linie einfügen</li>
</ul>
<p><b>Hilfe bei der Karte</b></p>
<ul>
	<li>Ein-/Auszoomen mit dem Mausrad.</li>
	<li>Karte mit linker Maustaste verschieben.</li>
	<li>Zoom-Rechteck mit Umschalt-linker Maus-Taste aufziehen.</li>
</ul>
<p class='hidelayer'><a href="javascript:hideLayer('help')"
	title="Hilfeseite verbergen">x</a></p>
</div>

<!-- display track length in km -->
<div id="tracklength" style='display:none'></div>

<!-- install the tool bar -->
<p id="toolbar"><span class="t0">
<!--
<a 	href="javascript:showUploadLayer();">einladen ...</a> </span>
-->
<a 	href="javascript:showLayer('uploadLayer', 'block')">einladen ...</a> </span>
<span class="t1">
<select id="trackoption">
	<option>track</option>
	<option>route</option>
</select>
<a class="1" title="speichere Route/Track lokal"
	href="javascript:gpxTrack.save()">speichern</a> <input id="routename"
	title="Namen eingeben" type="text" value="bitte Namen eingeben" maxlength="20" />
</span>
<span class="t0">
<a href="javascript:deleteVectorLayer()">Route(n) löschen</a>
</span>
<span class="t1">
<a title="Hilfeanzeige aus-/einschalten" href="javascript:toggleLayer('help', 'block');">Hilfe</a>
</span>
<!-- size functions for map -->
<span class="t0">
<a href="javascript:sizeMap(-100)" title="-100"><</a>
<a href="javascript:mapFullsize()" title="full size">Kartengröße</a>
<a href="javascript:sizeMap(+100)" title="+100">></a>
</span>
<!-- file upload -->
<div id='uploadLayer' class='fileinputs' style="display:block">
<p id='pickFile'>
<font face="Arial" size="-1">
Der GpX-Viewer befindet sich im Verzeichnis
<input id="path" type="text" size="100" maxlength="100" value="" readonly="readonly"><br>
Die Datei muss aus dem Unterverzeichnis <q>gpx</q> ausgewählt werden 
(Javascript Einschränkung). Bitte auf <q>Select</q> klicken ...</font>
</p>
<form name="uplform" class="uplform">
<div class="fileinputs">
<input class="file" id="gpxfile" type="file"/>
</div>
</form>
<div id='showFile'>
<input type='button' value="Anzeigen..." class='btn'
    onclick="loadGPX();" />
<input type='button' value="Abbrechen" class='btn'
	onclick="hideLayer('uploadLayer');" />
</div>
</div>
</body>
</html>

. Starten der Anwendung

Einfach im Explorer (Windows) oder Finder (Mac OS X) auf "ZeigeGPXaufOSM.htm" doppelklicken (alternativ natürlich auch aus dem Datei-Menü des Browsers). Nach dem Starten wählt man eine Datei aus und klickt auf "Anzeigen".

. Anmerkungen

Lief einwandfrei mit Safari und Firefox unter Windows XP und Mac OS X SnowLeopard. Internet Explorer und K-meleon hatten ihre Probleme ...

Einige Programmpunkte gehen noch nicht, siehe z.B. "Speichern".