E_WARNING: Parameter 1 to wp_default_scripts() expected to be a reference, value given
  Trace: plugin.php:580 class.wp-scripts.php:46 class.wp-scripts.php:34 functions.wp-scripts.php:201 header.php:14 template.php:501 template.php:477 general-template.php:47 single.php:1 template-loader.php:74 wp-blog-header.php:16 index.php:17
E_WARNING: Parameter 1 to wp_default_styles() expected to be a reference, value given
  Trace: plugin.php:580 class.wp-styles.php:39 functions.wp-styles.php:109 simpletb.php:112 plugin.php:505 functions.wp-styles.php:34 plugin.php:505 general-template.php:2065 header.php:15 template.php:501 template.php:477 general-template.php:47 single.php:1 template-loader.php:74 wp-blog-header.php:16 index.php:17

Bikekarte dank Google Fusion

Ich war diese Woche gesundheitlich nicht so fit, umso mehr Zeit hatte ich Codezeilen zu tippen. Ich habe die letzten Tage mit Google Fusion verbracht und bereits darauf aufmerksam gemacht.

Ich bin wieder einen Schritt weiter. Meine persönliche Bikekarte mit Google Maps API V3 und einer Google Fusion Tabelle ist live. Die Karte ist auch über diverse Parameter filterbar.

Meine Bikekarte zeigt mir alle meine Mountainbike Touren auf einmal auf der Karte, welche ich auf GPSies führe. Ich kann bequem nach Länge, Anstieg und höchsten Punkt filtern.
Coole Sache, Google. Das Ganze soll natürlich auch recht skalierbar sein.

Die Bikekarte wird von mir sicherlich noch erweitert werden. Als nächstes in der Reihe Google Fusion plane ich folgende Sachen:

  • eine ähnliche Karte mit den hier detailiert beschriebenen Touren (inkl. weiteren Filtern)
  • Highlighting der ausgewählten Strecke in der Karte
  • eine Karte und Umgebungsliste der Mountainbike Laden in der Schweiz*

* ride hat diese Liste auf ihrer Website, aber die Suche ist meiner Meinung nach suboptimal. Ist man unterwegs, möchte man in der Regel einfach die 5 nächstgelegenen Shops vom aktuellen Standort sehen. Ich werde dies mal versuchen und dann Ride informieren.

Detaillierter PHP Code

Für die Entwickler unter Euch, hier wie das Ganze detaillierter aussieht:

1. Daten von gpsies in eine google fusion tabelle einfügen

GPSies wie auch Google Fusion stellen beide eine API zur Verfügung.
Ich gehe davon aus, dass die Tabelle auf Fusion bereits besteht (diese kann sonst auch per API generiert werden).

$page = 0;
while (true) {
    $page++;

    // Strecken von GPSies auslesen
    $file = file_get_contents('http://www.gpsies.com/api.do?searchUsername=deineID&country=CH&trackTypes=mountainbiking&limit=100&resultPage=' . $page);
    $xml = simplexml_load_string($file);
    if (chop($xml->meta->resultSize) == 0)
        break;

    // kml der Strecke holen und Geoinformation speichern
    $gpsiesId = chop($track->fileId);
    $file = (file_get_contents('http://www.gpsies.com/download.do?filetype=kml&fileId=' . $gpsiesId);
    $kml = simplexml_load_string($file);
    $geo = '';

    foreach ($kml->Document->Folder->Placemark as $placemark) {
        if ($placemark->MultiGeometry->LineString) {
            foreach ($placemark->MultiGeometry->LineString as $line) {
                $geo .= chop($line->coordinates);
            }
        }
    }

    $values = array(
        'gpsiesid'  => $gpsiesId,
        'name'      => chop($track->title),
        'distance'  => round(chop($track->trackLengthM) / 1000, 1),
        'ascent'    => chop($track->totalAscentM),
        'elevation' => chop($track->altitudeMaxHeightM),
        'geometry'  => '' . $geo . '',
    );

    // Daten in Fusion Tabelle laden
    $keys = implode(", ", array_keys($values));
    $vals = implode("', '", $values);
    $command = "INSERT INTO " . $this->opts['tableId'] . " (" . $keys . ") VALUES ('" . $vals . "')";

    execFusion($command);

   // gpsies Server nicht überlasten
   sleep(2);
}

Für ein INSERT in Google Fusion braucht es eine Authentifizierung. Der Service heisst “fusiontables”.

Je nach Befehl (INSERT, UPDATE, …) muss die Query mit HTTP-POST oder GET ausgeführt werden.

function execFusion($command) {
    $auth = "das-ist-dein-schlüssel";

    $headers = array(
        "Authorization: GoogleLogin auth=" . $auth,
    );

    $curl = curl_init($this->baseurl);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

    // make post or get depending on command
    if (preg_match('!^(insert|update|delete)!i', $command))
        curl_setopt($curl, CURLOPT_POSTFIELDS, array('sql' => $command));
    else
        curl_setopt($curl, CURLOPT_URL, $this->baseurl . '?sql=' . urlencode($command));

    $return = curl_exec($curl);
    curl_close($curl);

    return $return;
}

2. Google Maps API V3 und Fusion Table

Das Einfügen der Fusion Table als Layer geht ziemlich einfach im Javascript:

    // Google Maps instanzieren
    var latlng = new google.maps.LatLng(46.798448583333, 8.2318785277778);
    var myOptions = {
            zoom: 8,
            center: latlng,
            mapTypeId: google.maps.MapTypeId.TERRAIN
    };
    var map = new google.maps.Map(document.getElementById("map"), myOptions);

    // Google Fusion anzeigen
    var fusionTableLayer = new google.maps.FusionTablesLayer(tableID);
    fusionTableLayer.setMap(map);

    // Filter (man muss die Spalte mit der Geoinformation selektieren, sonst gehts nicht)
    var query = "select geometry from " + tableID + " where distance < 30";
    fusionTableLayer.setOptions({ query: query });

3. Nachtrag Authentisierungs Key für Google Fusion erhalten

Den Key erhält man mit Hilfe von ClientLogin von Google. Beachte die auch die Service Namen.

function getAuth() {
    $clientlogin_url = "https://www.google.com/accounts/ClientLogin";
    $clientlogin_post = array(
        "accountType" => "GOOGLE", // HOSTED, GOOGLE, HOSTED_OR_GOOGLE
        "Email" => "your login",
        "Passwd" => "your password",
        "service" => "fusiontables",
        "source" => "some reference name of your app"
    );

    // Initialize the curl object
    $curl = curl_init($clientlogin_url);

    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $clientlogin_post);
    curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

    $response = curl_exec($curl);

    preg_match("/Auth=([a-z0-9_\-]+)/i", $response, $matches);
    $auth = $matches[1];

    return $auth;
}

2 Kommentare

  1. Klaus sagt:

    Salut Denis,

    eine Anmerkung hätte ich noch dazu. Der Server von API-GPSies ist der gleiche, der auch die Webseiten ausliefert. Alle Downloads werden auf dem Server dynamisch zur Laufzeit erzeugt. Es wäre super, wenn ihr bei der Iteration eine gewisse Zeit pausiert, bevor ihr euch den nächsten Track abholt. Am liebsten wären mir 2000 ms :-). Wenn ihr das nicht beachtet, könnt ihr den GPSies-Server lahmlegen. Dann müsste ich leider eure IP oder gleich die ganze die API sperren… – Web-Betrieb geht vor.

    Trotzdem – toller Artikel! Ich selbst bin mit den Google-Fusion-Table-Entwicklern (Geo) in San Francisco in Kontakt und wir überlegen eine Methode, wie man alle 400.000 Tracks von GPSies auf einmal darstellen kann ;-)

    LG, Klaus

  2. 2ni sagt:

    Hi Klaus, ok danke für den Hinweis. Der Import war einmalig, aber ich hab im Skript nun ne Pause von 2000ms eingebaut pro Trackdownload. Sorry falls es gestört hat! Übrigens ist das Laden in Google Fusion auch nicht so schnell, da gibts also auch ne “automatische” Pause.