POIs/Polylines nur je Kartenausschnitt laden

Hallo zusammen,

ich habe hier im Forum vor einiger Zeit einmal einen Beitrag gefunden der recht gut veranschaulichte, wie man realisieren kann, dass POIs oder Polylines dynamisch aus einer DB geladen werden und zwar immer in Abhängigkeit des Kartenabschnitts, so dass tatsächlich nur die relevanten Daten geladen werden. Da ich mit GPX Tracks arbeite, die sehr lang werden, habe ich das bisher so gelöst, dass ich nur Marker setze. Das hat mit einem hier gefundenen Hinweis/Beitrag sehr gut geklappt. Allerdings würde ich das nun gerne einmal mit einer Polyline versuchen, aber mir fehlt hier irgendwie der richtige Ansatz bzw. Einsprungspunkt.

Kennt jemand ein Beispiel oder hat einen Rat, den ich mir mal zu Gemüte führen kann?

Danke im Voraus - und einen schönen Start ins Wochenende :slight_smile:

Mein Rat ist, dass du erstmal ein Beispiel lieferst :wink: Ohne zumindest etwas davon zu wissen, wie dein Umfeld aussieht, kann dir wohl niemand helfen.

  • Web-Anwendung mit Openlayers oder Leafleat?
  • Rendern eigener Karten mit Mapnik & Co ?
  • iPhone- oder Android-APP?
  • ???
  • ???

danach gehts weiter:

  • wo sind die Daten?
  • wie greifst du drauf zu
  • ???

Gruss
Walter

wenn es eine Openlayers-Anwendung mit einer DB auf dem eigenen Server wäre:


      var pcnodes = new OpenLayers.Layer.Vector("Nodes", {
                       	displayInLayerSwitcher: true,
                       	isBaseLayer:		false,
		       	visibility:		true,
                	numZoomLevels:		19,
       			permalink: 		"nodes",
           		maxResolution: 		resolutions[14], 
			projection:		projfrom,        
            		strategies:		[new OpenLayers.Strategy.BBOX({ratio: 1, resFactor: 1.1})],
            		protocol:		new OpenLayers.Protocol.HTTP({
             			url:		"getPostalCodeNodes",  
             			format:		new OpenLayers.Format.GeoJSON()
             	        })            
      });

Wichtige Punkte:

  • OpenLayers.Layer.Vector
  • OpenLayers.Strategy.BBOX
  • OpenLayers.Format.GeoJSON()

Am Server kommt dann so eine Query an: http://localhost:8080/getPostalCodeNodes/?bbox=8.0804583530426,50.104261318697,8.115112493515,50.116728784895
d.h. openlayers fügt selber die bbox ein
Mein Server schickt dann das Ergebnis im json-Format zurück und Openlayers macht den Rest.

Gruss
Walter

Nahmd,

Du suchst das hier. Es benutzt die von Wambacher vorgeschlagen Klassen “OpenLayers.Layer.Vector” und “OpenLayers.Strategy.BBOX”, dann aber “OpenLayers.Format.GPX” statt “OpenLayers.Format.GeoJSON”, was den Ablauf im Browser ein wenig verlangsamt.

Da im schlimmsten Falle (zoom=0) die BBOX die ganze Welt umfasst, würden in diesem Fall immer alle Punkte der Linie übertragung, was spätestens bei 100000 Stück den Browser verstimmt. Deshalb lasse ich den Server – listig, listig – nur eine Auswahl der Punkte liefern: damit kann man einen beliebig langen Weg über alle Zoomstufen hinweg anzeigen.

Nun zu den schlechten Nachrichten:

  1. ich habe die serverseitige Unterstützung nur als Perl-CGI vorlegen und nicht als PHP-Skript.
  2. ich will kann nicht bei der Zusammenstellung der Punkte zum Beispiel aus einer Relation helfen.

Das erste Problem lässt sich allerdings lösen: durch Bestechung mit einer Tüte Gummibärchen oder (besser) durch das Versprechen, den Ablauf im Wiki zu dokumentieren.

Gruß Wolf

Eventuell noch “listiger”:



irgendwo weiter oben im html-code:
 
var resolutions =       [156543.03390625, 78271.516953125, 39135.7584765625,
                               19567.87923828125, 9783.939619140625, 4891.9698095703125,
                               2445.9849047851562, 1222.9924523925781, 611.4962261962891,
                               305.74811309814453, 152.87405654907226, 76.43702827453613,
                               38.218514137268066, 19.109257068634033, 9.554628534317017,
                               4.777314267158508, 2.388657133579254, 1.194328566789627,
                               0.5971642833948135];

und dann das maxResolution: resolutions[14] aus dem obigen Beispiel und schon wird der Server gar nicht mehr belästigt, wenn das Zoomlevel kleiner als 14 ist.

Kommt aber wohl auf die Zielsetzung an: Ich blende Daten bei kleineren Zoomstufen aus und Wolf schein die dann zu generalisieren. Auch ein schöner Ansatz. Man könnte bei punktförmigen Informationen auch clustern aber hier geht es ja um Ways.

Gruss
walter

p.s. json hab ich nur als Beispiel genommen; gpx oder sogar osm geht auch, wenn man einen Server hat, der sowas liefern kann.

Nahmd,

Wobei ich es gerade witzig finde, dass auf der Weltkarte der Weg noch zu sehen ist.
Beim Hanseweg nur als Punkt, die E1, E4 & CO opder der Appalachian Trail sollten sehr schön zu sehen sein.

Json ist die beste Lösung, zum einen weil Du das über den fiesen “-Befehl erzeugen”-Trick von einem anderen Server nachladen kannst – und das wird spätestens dann wichtig, wenn der OP mit einem Punktfilter ausgestattet wird –, und zum zweiten, weil (wenn man mutig genug ist, das json per eval() auszuwerten,) es deutlich schneller ist.

Gruß Wolf

Dass ich GPX benutzt habe, liegt – peinlich, peinlich, aber zum Glück liest das ja keiner – daran, dass ich das GPX-Format auswendig kenne, das Json aber hätte nachschlagen müssen.

da du ja auch mit postgresql und postgis arbeitest:


select id, 
       st_astext(linestring),
       ST_AsGeoJSON(linestring,5),
       ST_AsGeoJSON(ST_Centroid(linestring),5)
  from ways
 where id=99;

 99 | LINESTRING(11.3661581 48.1741769,11.366186 48.1741419,11.3662301 48.1741153,11.3662851 48.1741004,11.3663747 48.1741024,11.3664153 48.1741169,11.3664584 
48.1741442,11.3664849 48.1741796,11.3664895 48.1742311,11.3664696 48.1742684,11.3664317 48.1742989,11.3663804 48.1743189,11.3663076 48.1743257,11.36625 
48.1743158,11.366201 48.1742934,11.3661665 48.1742612,11.3661506 48.174223,11.3661581 48.1741769) | 

{"type":"LineString","coordinates":[[11.36616,48.17418],[11.36619,48.17414],[11.36623,48.17412],[11.36629,48.1741],[11.36637,48.1741],[11.36642,48.17412],[11.36646,48.17414],
[11.36648,48.17418],[11.36649,48.17423],[11.36647,48.17427],[11.36643,48.1743],[11.36638,48.17432],[11.36631,48.17433],[11.36625,48.17432],[11.3662,48.17429],[11.36617,48.17426],
[11.36615,48.17422],[11.36616,48.17418]]} | 

{"type":"Point","coordinates":[11.36632,48.17421]}

Noch einen kleinen json-Rahmen drum bauen, fertig. was will man mehr :wink:

Gruss
walter

Nahmd,

Nö. NOSQL-Datenbank.


[...]snip[...]

Mach das mal mit 100.000 Punkten. :stuck_out_tongue:
Mit dem Browser von jemandem, den Du nicht leiden kannst.

Guck Dir die Version ohne Preprocessing an:

  1. die kann (“Please zoom in to view data”, yeah!) nicht den Weg als Ganzes darstellen. Das ist Mist.

  2. das Ergebnis sieht suboptimal aus. Weil da ich weiss nicht wie viele einzelne Linien gezeichnet werden, und an der Stoßstelle von zwei teiltransparenten Linien ein Kreis mit geringerer Transparenz entsteht. Der Weg ist also mit Flecken gesprenkelt, die nichts mit der Route zu tun haben, sondern reine Artefakte aus der Struktur der Speicherung der Daten sind.

Dafür wird dieser Wanderweg minutenaktuell dargestellt. Da kann ich wegen des Preprocessings nicht mithalten. Allerdings glaube ich auch nicht, dass die Routenführung minütlich geändert wird.

Gruß Wolf

sowas macht man doch nicht, dann wird geklustert. Bei 100k Nodes geht jeder Browser in die Knie.

ganz banaler Vorschlag: opacity=1, da können sich noch so viel Kreise überlappen: blau bleibt blau, blauer wird’s nicht.

Nahmd,

Ich spreche nocht von 100.000 POIs, sondern von einer Linie mit 100.000 Punkten.

Aber selbst, wenn es POIs-wären: die Cluster-Strategie hilft bei der Anzeige, wenn zu viele Objekte übereinandergezeichnet werden. Aber nicht beim Traffic und auch nicht bei der vom Browser zu handelnden Datenmenge. Probier es aus.

Das ist korrekt. Weiterer Vorteil: man muss die blöden Straßennamen unter der Linie nicht mehr lesen.

Ich ahne übrigens schon, was jetzt kommen wird: “dann machen wir die Linie halt nur 0.5 Pixel breit.”

Es ist wirklich erstaunlich, welche Nachteile in Kauf genommen werden, nur um direkt mit OSM-Rohdaten arbeiten zu können.

Gruß Wolf

Edit: Ironiemarker eingefügt

Nahmd,

Das ist richtig.

Der Browser ist aber nicht wirklich glücklich, wenn er erst einmal 100.000 Punkte (denn das Thema war: lange Tracks) abholen und bearbeiten darf.

Das ist nicht ganz richtig:

Gruß Wolf

ok, ich ab jetzt auch :wink:

hab ich längst und bin dann zum Clustern auf dem Server gewechselt. Und genau das hab ich bei meiner Antwort (“Cluster doch einfach”) vergessen. 100k Nodes zum Browser hochzujagen und ihn dann bitten, das gefälligst zu clustern, ist wohl nix. Schwamm drüber.

naja, ich denke mir mal … und dann passt das schon. :wink:

Ist ja nicht deine Schöpfung und Jan wird das auch irgendwann mal hinkriegen. Da hilft es wirklich nur, den Job dem Server zu überlassen.

Gruss
walter

Hallo zusammen,

vielen Dank zunächst für die ausführlichen Informationen.

Wie immer in diesen Forum hat das eine ganze Menge Licht ins Dunkel gebracht.

@wambacher
Sorry für meine spärliche Beschreibung meines Eingangsposts, das passiert, wenn man einen solchen Beitrag zwischen Tür und Angel schreibt -.-

Grob gesagt: Hole Wegpunkte aus einer DB, und stelle diese auf einer Webseite als Linestring da.

Beitrag #3 von Netzwolf hat aber im Grunde genau das aufgegriffen, was ich gesucht habe.
Nachdem ich mir die OpenLayers.Format.GeoJSON sowie OpenLayers.Strategy.BBOX näher angeschaut habe - zumindest soweit um Verständnis dafür zu entwickeln, da dies Neuland für mich ist, konnte ich anfangen, mein Anliegen umzusetzen, zumal ich das GeoJSON auch an anderer Stelle sehr gut gebrauchen kann.

Das weglassen von Daten je nach Zoomstufe ist natürlich eine nette Idee, schade, dass ich da nicht selbst drauf gekommen bin.
Also eine kleine (zunächst zu Testzwecken) PHP Datei geschrieben, um zu schauen, was beim JSON Request an Daten übertragen wird.

Dann anhand der “mindist” einen kleinen Filter definieren, welche Daten nach welchem Muster ignoriert werden sollen und wieviele.

Bei mindist-31250 z.B. habe ich quasi ganz Europa auf dem Schirm, bei 10 Tracks, die jeweils 400.000 Werte umfassen, muss ich hier natürlich knallhart Daten “droppen”, als Vorfilter schwebt mir hier vor nur jeden 10.000sten Datenpunkt in den Linestring einfließen zu lassen, was man prima mit Modulo lösen könnte.

Wichtig ist, dass nicht erst xx-Tausend Werte am Browser ankommen, die dann dort prozessiert werden sollen, aber ich denke, das klappt mit oben gennanter Lösung sehr gut.

Was mich jetzt an dieser Stelle aber interessieren täte ist, ob ich - das konnte ich beispielsweise meinen Recherchen zum Thema noch nicht entnehmen, auch Funktionen in Javascript implmentieren kann, als einfaches Beispiel z.B., dass ein Klick auf eine Linie einfach die Funktion alert aufruft und mir stupide die Koordinaten anzeigt. Gibt es für sowas einen Workaround?

Nahmd,

Zur Klasse “OpenLayers.Layer.Vector” gibt es die praktische Ergänzung “OpenLayers.Control.SelectFeature”. Die kümmert sich um sowas. Hier nur als Mouseover. Die kann aber auch Klick.

Deinem Wunsch besser entspricht das hier (auf Track klicken). Die Implementierung ist aber uralt und Mist, das sollte heute viel einfacher mit Bordmitteln von Layer.Vector/Control.SelectFeature gehen.

Gruß Wolf

Edit: zweites Beispiel ergänzt.

Nahmd,

Wenn ich was baue, setze ich ein Timelimit von 0.3s. Alles was darüber geht, braucht einen wirklich guten Grund. Und mehr als 1s ist völlig inakzeptabel. Vielleicht habe ich deshalb so heftig reagiert. Sorry. :confused:

Ich würd’ da nicht üder das JS böse sein. Ich findes es absolut beeindrucken, wie schnell das heute ist. Auf der Höhenbeschränkungskarte ist das geradezu unglaublich. Also dem auch mal ein Hängen nachsehen. Und nicht mit mit überflüssigen Daten malträtieren :wink:

Das braucht keine Datenbank. Die Daten kann man von OP oder (in diesem Fall) ganz trivial vom OSM-DB-Server ziehen (letzteres hatte ich gemacht). Der Aufwand ist gewiss nicht überzogen, wenn man damit ein Seite mit guter Usability erzeugt.

Auch einmal je Tag. Oder je Stunde. Nichts davon tut dem Server weh, von dem man die Daten zieht. Und auf dem Server des Nutzers braucht die Aufbereitung nur Sekunden.

Genau das ist völlig überzogen. :slight_smile:

Du kannst ein PostGIS mit Aktualisierung aufsetzen und Readonly-Zugriffe von außen anonym oder nach Registrierung oder mit dem OSM-Account erlauben. Ich kann auch hoch und heilig versprechen, dass es einen ersten Nutzer gibt. :slight_smile:

Gruß Wolf

Ich versuche gerade krampfhaft, dein GPX Beispiel nachzuvollziehen (http://www.netzwolf.info/kartografie/openlayers/tracks.htm)

Klappt, unterbringen von zusätzlichen Werte in der GPX Datei sowie Zugriff auf den entsprechenden Wert via feature.attributes[‘xyz’] klappt auch. Bis dahin schon einmal super.

Aber ganz im Gegensatz zu deinem JSON Beispiel klappt das mit dem dynamischen Laden der Daten nicht mehr.

In deinem JSON Beispiel wird beim Verschieben bzw. Ändern des Zooms wie gewünscht ein neuer Request erzeugt.

Beim GPX Beispiel funktioniert dies jedoch nicht. Ist das grundsätzlich so vorgesehen?

Liegt das am strategies: [new OpenLayers.Strategy.Fixed()] anstelle strategies: [new OpenLayers.Strategy.BBOX({resFactor: 1.0 })]?

Denn tausche ich Fixed() gegen BBox(…) bleibt die Karte dunkel (Scriptfehler bekomme ich jedoch keine.

Anbei meine verzweifelte Zusammenwürfelei:


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<title>Trackdecoder</title>

<script type="text/javascript" src="http://www.openlayers.org/api/OpenLayers.js"></script>
<script type="text/javascript" src="http://www.openstreetmap.org/openlayers/OpenStreetMap.js"></script>


<!--==================================================================================
"loadstatus.js" enthaelt die Definition der Klasse
	"OpenLayers.Control.LoadStatus".
Diese Klasse implementiert eine Lade-Statusanzeige.
Bitte kopiere die JavaScript-Datei auf den eigenen Server. Danke.
In den mit "#######" markierten Zeile wird der LoadStatus aktiviert.
===================================================================================-->

<script type="text/javascript" src="js/load.js"></script>


<!--==================================================================================
Erweiterung zum Format "GPX": liefere Liste aller Segmente.
===================================================================================-->


<script type="text/javascript">
OpenLayers.Format.GPX.prototype.extractSegment= function (segment,segmentType) {

	var points=this.getElementsByTagNameNS(segment,segment.namespaceURI,segmentType);
	var point_features=[];

	for (var i=0,len=points.length;i<len;i++){

		var point = points[i];
		var geo = new OpenLayers.Geometry.Point(point.getAttribute("lon"),point.getAttribute("lat"));
		point_features.push(geo);
		var attributes={};
		var attCount=0;

		for (var attrNode=point.firstChild; attrNode; attrNode=attrNode.nextSibling) {
    //alert( attrNode.text);
			if (attrNode.nodeType!=1) continue;
			var valueNode=attrNode.firstChild;
			if(valueNode.nodeType!=3&&valueNode.nodeType!=4) continue;
			var value = valueNode.nodeValue;
      //alert(attrNode.nodeName);
			switch (attrNode.nodeName) {
     
			case 'ele':
				attributes.ele = Math.round(parseFloat(value));
       
				break;
    
			case 'time':
				unixtime = Date.parse(value);
				attributes.time = unixtime ? new Date (unixtime) : null;
				break;  
        case 'speed':
				attributes.speed = value;
        
			}
			attCount++;
		}
		if (attCount) geo.attributes=attributes;
	}
	return new OpenLayers.Geometry.LineString(point_features);
};
</script>


<script type="text/javascript">
//------------------------------------------------------------------------------------
//	Die anonyme Onload-Function baut das Kartenobjekt aus Komponenten zusammen.
//	An der mit "***" markierten Zeile tragen Sie die URL *Ihrer* GPX-Datei ein.
//------------------------------------------------------------------------------------

var map;

window.onload = function () {

	//----------------------------------------------------------------------------
	//	Karte - der Name ('map') muss mit der id des <div> uebereinstimmen.
	//----------------------------------------------------------------------------

	map = new OpenLayers.Map ('map');

	//----------------------------------------------------------------------------
	//	Default-Koordinatensystem fuer alle Controls
	//----------------------------------------------------------------------------

	map.displayProjection = new OpenLayers.Projection('EPSG:4326');

	//----------------------------------------------------------------------------
	//	Steuerelemente
	//----------------------------------------------------------------------------

	map.addControl (new OpenLayers.Control.LayerSwitcher());
	map.addControl (new OpenLayers.Control.LoadStatus());		//#######

	map.addLayer (new OpenLayers.Layer.OSM.Mapnik("Mapnik"));

	//----------------------------------------------------------------------------
	//	Kartenlayer
	//----------------------------------------------------------------------------

	map.addLayer (new OpenLayers.Layer.OSM.Mapnik('Mapnik'));

	//----------------------------------------------------------------------------
	//      Vector (GPX) Layer
	//	die Karte zoomt automatisch auf den Umriss des Tracks
	//----------------------------------------------------------------------------

	var track = new OpenLayers.Layer.Vector("Route", {


		strategies: [new OpenLayers.Strategy.Fixed()],

		protocol: new OpenLayers.Protocol.HTTP({

			url: "route.php",
      	params: {
				format: 'gpx',
				mindist: 1e6
			},
			format: new OpenLayers.Format.GPX({

				extractWaypoints: true,
				extractRoutes: true,
				extractTracks: true,
				extractAttributes: true
			})
		}), 
    
		moveTo: function (bounds, zoomChanged, dragging) {

                	if (zoomChanged) {

				this.protocol.params.mindist = 1000000 / Math.pow(2, this.map.getZoom());
       alert(bounds);
			}

			OpenLayers.Layer.Vector.prototype.moveTo.apply(this, arguments);
		},

		style: {
			fillColor: "#000000",
			strokeColor: "#ffff00",
			strokeDashstyle: "#LTYPE",
			strokeWidth: 5,
			strokeOpacity: 1.0,
			pointRadius: 5
		},

		zoomMapToMyBounds: function () {

			bounds = this.getDataExtent();
			if (bounds) {
				this.map.zoomToExtent(bounds);
			} else {
				this.map.zoomToMaxExtent();
			}
		}
    
    
	});

	track.events.register("loadend",track,track.zoomMapToMyBounds);
	map.addLayer (track);

	//-----------------------------------------------------------------
	//	Erzeuge Popup
	//-----------------------------------------------------------------

	function createPopup(feature) {

		//-----------------------------------------------------------------
		//	Position des Klicks in Kartenkoordinaten
		//-----------------------------------------------------------------

		var hotspot = this.map.getLonLatFromPixel(this.lastXy);

		//-----------------------------------------------------------------
		//	Suche nach naechster Feature-Geometrie-Komponente
		//-----------------------------------------------------------------

		var nearestComponent=null;
		var minDistance=null;

		//-----------------------------------------------------------------
		//	Iteriere über alle Komponenten
		//-----------------------------------------------------------------

		if (feature.geometry && feature.geometry.components) {

			for (var i=0; i<feature.geometry.components.length; i++) {

				var component = feature.geometry.components[i];
				if (!component.attributes) { continue; }

				var distance=
					(hotspot.lon-component.x)*(hotspot.lon-component.x)+
					(hotspot.lat-component.y)*(hotspot.lat-component.y);

				if (minDistance!=null && minDistance < distance) continue;

				nearestComponent=component;
				minDistance=distance;
			}
		}

		//-----------------------------------------------------------------
		//	Speichere Position der naechsten Komponente
		//-----------------------------------------------------------------

		if (nearestComponent) {

			hotspot.lat = nearestComponent.y;
			hotspot.lon = nearestComponent.x;
		}

		//-----------------------------------------------------------------
		//	Konvertiere nach Geographischen Koordinaten
		//-----------------------------------------------------------------

		var pos = hotspot.clone();
		if(this.displayProjection) {

			pos.transform(this.map.getProjectionObject(),this.displayProjection);
		}

		//-----------------------------------------------------------------
		//	Beginne Popup-<div>
		//-----------------------------------------------------------------

		text = '<div>';

		//-----------------------------------------------------------------
		//	Name des Features
		//-----------------------------------------------------------------

		text += '<h3>'+feature.attributes.name+'<'+'/h3>\n';

		//-----------------------------------------------------------------
		//	Weitere Attribute des Features
		//-----------------------------------------------------------------

		if (feature.attributes)  {

			for (var tag in feature.attributes) {

				if (tag != '') {
					text += tag+': '+feature.attributes[tag]+'<br />\n';    //
           document.getElementById('ele').innerHTML = feature.attributes['speed'];
           if (tag == 'speed') {
           alert(feature.attributes[tag]);
           }
           
          
         
				}
			}
		}

		//-----------------------------------------------------------------
		//	Naechstliegende Komponente des Features
		//-----------------------------------------------------------------

		if (nearestComponent) {

			text += '<hr />Lat/Lng: '+(pos.lat<0?'S':'N')+Math.abs(pos.lat)+' '+(pos.lon<0?'W':'E')+Math.abs(pos.lon)+'<br />';

			for (var tag in nearestComponent.attributes) {
				text += tag+': '+nearestComponent.attributes[tag]+'<br />\n'; 
         if (tag == 'speed') {
         document.getElementById('ele').innerHTML = nearestComponent.attributes[tag];
   
           } 
			}
		}

		//-----------------------------------------------------------------
		//	Schliesse Popup-<div>
		//-----------------------------------------------------------------

		text += '<'+'/div>';
    
		//-----------------------------------------------------------------
		//	Erzeuge Popup
		//-----------------------------------------------------------------

		feature.popup = new OpenLayers.Popup.FramedCloud("gpx",
			hotspot,
			null,
			text,
			null,
			true,
			function() { selcontrol.unselectAll(); }
		);

		//-----------------------------------------------------------------
		//	Zeige Popup
		//-----------------------------------------------------------------

		map.addPopup(feature.popup);
	}

	//-----------------------------------------------------------------
	//	Zerstoere Popup
	//-----------------------------------------------------------------

	function destroyPopup(feature) {

		feature.popup.destroy();
		feature.popup = null;
	}

	//-----------------------------------------------------------------
	//	automatisches Anlegen der Controls fuer die Tracks
	//-----------------------------------------------------------------

	var selcontrol = new OpenLayers.Control.SelectFeature([track], {

		onSelect: createPopup,
		onUnselect: destroyPopup,
		lastXy: null,
		storePosition: function (evt) { this.lastXy=evt.xy; }
	});

	//-----------------------------------------------------------------
	//	([url]http://wiki.openstreetmap.org/wiki/User:MHohmann[/url])
	//-----------------------------------------------------------------

	map.addControl(selcontrol);

	//-----------------------------------------------------------------
	//	Aktuelle Position
	//-----------------------------------------------------------------

	map.events.register('mousemove',selcontrol,selcontrol.storePosition);

	//-----------------------------------------------------------------
	//	Aktivieren
	//-----------------------------------------------------------------

	selcontrol.activate();
};
</script>

<style type="text/css">
.olControlLoadStatus {
	left: 50px;
	top: 10px;
}
</style>
</head>

<body style="margin: 0">

<div style="float:right"><a href="http://www.netzwolf.info/kartografie/openlayers/">zur &Uuml;bersicht</a></div>
<h1>Trackdecoder</h1>

<div id="map" style="background: gray; width: 100%; height: 75%;"></div>

<p>
Klick auf Track zeigt im Popup Detail-Informationen.
</p>

<p>
Erkl&auml;rung im Quelltext der Seite.
</p>

<div id=ele>
</div>

</body>
</html>


Nahmd,

Sehr schön.

Das hat nicht direkt etwas mit Json/Gpx zu tun, sondern ich hab einfach keine Serverseitige Unterstützung dafür, BBOX-Ausschnitte aus GPXen zu liefern.

Ja.

“Strategy.Fixed” (ein toller Name für eine Banalität) holt die angegebene URL genau einmal ab und ist danach zufrieden. Der Server braucht nur zur URL die Daten rauszurücken und gut ist. Keine Intelligenz gefordert.

Die Strategie Bbox fragt beim Start und später bei (fast) jedem Zoom/Pan die Daten neu ab. Dabei hängt sie an die URL einen Parameter “bbox=W,S,E;N” an. Ein Script/Programm/Servlet auf dem Server soll dann die Daten bereitstellen, die in der angegebenen BBOX liegen.

Der Grund für die dunkle Karte ist der Münchhausen-Effekt. Jedenfalls habe ich den so getauft, nachdem ich mehrmals darauf reingefallen bin:

Damit die Karte dargestellt werden kann, braucht es Koordinaten und eine Zoomstufe. Solange die nicht angegeben werden, gibt es auch keine Karte. Und solange keine Karte dargestellt wird und es damit keine aktuelle BBOX gibt, holt die BBOX-Strategie auch nichts ab (Du kannst ins Server-Log gucken – da ist keine Anfrage).

Die Fixed-Strategie dagegen interessiert sich überhaupt nicht für die Karte und ruft stupide nach der Initialisierung die URL ab.

Im GPX-Beispiel (Fixed) habe ich die Zeile


track.events.register("loadend",track,track.zoomMapToMyBounds);

Übersetzt: ruf nach dem Laden des GPX die zoomMapToMyBounds-Methode auf. Die holt sich die Ausmaße des geladenen GPX und zoomt/pant die Karte so, dass das GPX optimal passt.

Der Ablauf also:

→ Strategy.Fixed ruft GPX ab (bedingungslos)
→ Map wird auf Bbox des Gpx dimensioniert.
→ Map wird gezeichnet.
:slight_smile:

Ablauf bei Strategy.BBOX:

→ Karte hat keine Größe
→ Ohne Kartengröße ruft Strategy.BBOX die URL nicht ab.
→ Ohne geladenes GPX wird zoomMapToMyBounds nicht aufgerufen
→ ohne zoomMapToMyBounds bekommt die Karte keine Größe.
→ wiederhole ad infinitum
:frowning:

Da versucht sich jemand an den eigenen Haaren aus dem Sumpf zu ziehen. :stuck_out_tongue:

Einfache Lösung: wenn Du die Strategy.BBOX verwendest, musst Du der Karte eine Größe geben. Ist wenn es einmal weiß ja auch vollkommen klar, dass die Kartengröße nicht aus den geladenen Daten bestimmt werden kann, wenn die geladenen Daten von der Kartengröße abhängen.

In meinem Strategy.BBOX-Beispiel findest Du am Ende des JS:


if (!map.getCenter()) {
	map.zoomToExtent(
		new OpenLayers.Bounds(9.98, 53.47, 14.49, 54.33).
	transform(map.displayProjection, map.getProjectionObject()));
}

Das “map.zoomToExtent” sorgt dafür, dass der angegebene Bereich möglichst groß zentriert dargestellt wird. Das “if (!map.getCenter()) {” drum herum unterdrückt die Positionierung, wenn die Seite über einen Permalink aufgerufen wurde.

Ich hoffe, Du kommst damit weiter.

Gruß Wolf

Und auch an dieser Stelle wieder ein großes Dankeschön.

Nun klappt es nahezu perfekt.

Darf ich dich nach deinem “Algorithmus” fragen, mit dem du die Daten beim Generieren “generalisierst”?

Ich mache das nun testweise, indem ich den Timestamp (zu dem die Koordinate gespeichert wurde) per Modulo herausfiltere. Das hat aber zur Folge, dass bei jedem Zoomwechsel andere Linestrings erzeugt werden, was ein wenig unbefriedigend auf der Karte aussieht, quasi wie ein Netz, dass immer wieder anders aufgebaut wird.

Nahmd,

Konzeptionell läuft es so ab (die Implementierung fasst die Schritte natürlich zusammen):

Der Client übergibt die bbox und die mindist.

Im ersten Schritt werfe ich alle Punkte außerhalb der Bbox weg bis auf die, die direkte Nachbarn eines Punktes innerhalb der Bbox sind. Dabei kann die Linie in mehrere Teile zerfallen.

Der Hanseweg z.B. hat Schlenker nach Norden, wenn ich mich darunter positioniere, läuft der Weg oben aus der Bbox raus und kommt wieder rein.

Von jeder Teillline nehme ich den Startknoten und den Endknoten immer in das Ergebnis auf.

Jetzt beginne ich am Startknoten und suche den ersten Nachfolgeknoten, der mindestens die “mindist” entfernt ist.

Ich zähle also nicht Knoten ab, sondern beziehe auch den Abstand zwischen den Knoten ein. Das Segment zwischen zwei Knoten kann ein langer gerader Weg sein (mal nach Stellweg im Siebengebirge suchen), oder ein Stück einer Serpentinenkurve mit Dezimeterlänge.

Den ersten Knoten im Abstand mindist nehme ich in die Ergebnisliste auf und suche von da aus wieder den nächsten Knoten mit Mindestabstand.

Alles sehr einfach.

.oO( Mist! Jetzt kann ich es nicht mehr patentieren lassen. :wink: )

Bei mir werden bereits bei einem Pan anderes Stützpunkte gewählt. Außerdem schaue ich mir bei jeder Auflösung alle Knoten an. Das geht bei den 9000 der Hanseweg noch (ist aber grob ungehörig), die Chinesische Mauer jedoch kann ich so nicht mehr handhaben.

Die Lösung dafür ist auf Papier schon fertig und harrt nur noch des eingetippert werdens.

Gruß Wolf

Nahmd,

Der Vorteil des Greedy-Algorithmus besteht darin, dass der nicht nur dieses Probleme löst, sondern auch fast alle anderen. :slight_smile:
Deshalb muss ich nicht so viele Algorithmen kennen. :sunglasses:

Gruß Wolf

@Netzwolf

Ich habe mich in den vergangenen Tagen wieder ein wenig ausführlicher mit der Thematik auseinander gesetzt.
Würdest du das CGI Script aus deinem Beitrag #3 zur Verfügung stellen?
Ich würde das dann in PHP übersetzen. Natürlich unter den von dir genannten Kriterien :wink: