Tuesday, August 13, 2013

Embed Google PageSpeed Insights in JavaFX WebView

Google's PageSpeed Insights is a tool that helps developers optimize their web pages by analyzing the pages and generating tailored suggestions to make the pages faster. You can use the PageSpeed Insights API to programmatically generate PageSpeed scores and suggestions.

Using Insights API, it's easy to embed the result to JavaFX application with WenView. This example demonstrate how to do it.

Embed Google PageSpeed Insights in JavaFX WebView
Embed Google PageSpeed Insights in JavaFX WebView
To acquire an API key, visit the APIs Console. In the Services pane, activate the PageSpeed Insights API; if the Terms of Service appear, read and accept them.

Next, go to the API Access pane. The API key is near the bottom of that pane, in the section titled "Simple API Access."

After you have an API key, your application can append the query parameter key=yourAPIKey to all request URLs.

Create HTML file, PageSpeedTest.html, to be embedded in WebView, with Javascript code of Insights API. Basically, it copy the example code from PageSpeed Insights Developer's Guide (v1) with little bit modification. You have to insert your API key in API_KEY.

<!DOCTYPE html>
<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

        <script>
            // Specify your actual API key here:
            var API_KEY = 'insert your API key here';

            // Specify the URL you want PageSpeed results for here:
            var URL_TO_GET_RESULTS_FOR = 'http://java-buddy.blogspot.com/';
        </script>

        <script>
            var API_URL = 'https://www.googleapis.com/pagespeedonline/v1/runPagespeed?';
            var CHART_API_URL = 'http://chart.apis.google.com/chart?';

            // Object that will hold the callbacks that process results from the
            // PageSpeed Insights API.
            var callbacks = {};

            // Invokes the PageSpeed Insights API. The response will contain
            // JavaScript that invokes our callback with the PageSpeed results.
            function runPagespeed() {

                alert('runPagespeed()');
                document.getElementById('testedurl').innerHTML = URL_TO_GET_RESULTS_FOR;

                var s = document.createElement('script');
                s.type = 'text/javascript';
                s.async = true;
                var query = [
                    'url=' + URL_TO_GET_RESULTS_FOR,
                    'callback=runPagespeedCallbacks',
                    'key=' + API_KEY
                ].join('&');
                s.src = API_URL + query;
                document.head.insertBefore(s, null);
            }

            // Our JSONP callback. Checks for errors, then invokes our callback handlers.
            function runPagespeedCallbacks(result) {

                alert('runPagespeedCallbacks(result)');

                if (result.error) {

                    alert('result.error');

                    var errors = result.error.errors;
                    for (var i = 0, len = errors.length; i < len; ++i) {
                        if (errors[i].reason === 'badRequest' && API_KEY === 'yourAPIKey') {
                            alert('Please specify your Google API key in the API_KEY variable.');
                        } else {
                            // NOTE: your real production app should use a better
                            // mechanism than alert() to communicate the error to the user.
                            alert(errors[i].message);
                        }
                    }
                    return;
                }

                // Dispatch to each function on the callbacks object.
                for (var fn in callbacks) {
                    var f = callbacks[fn];
                    if (typeof f === 'function') {
                        callbacks[fn](result);
                    }
                }

                alert('runPagespeedCallbacks(result) finished!');
            }

        </script>

        <script>
            callbacks.displayPageSpeedScore = function(result) {
                var score = result.score;
                // Construct the query to send to the Google Chart Tools.
                var query = [
                    'chtt=Page+Speed+score:+' + score,
                    'chs=180x100',
                    'cht=gom',
                    'chd=t:' + score,
                    'chxt=x,y',
                    'chxl=0:|' + score
                ].join('&');
                var i = document.createElement('img');
                i.src = CHART_API_URL + query;
                document.body.insertBefore(i, null);
            };
        </script>

        <script>
            callbacks.displayTopPageSpeedSuggestions = function(result) {
                var results = [];
                var ruleResults = result.formattedResults.ruleResults;
                for (var i in ruleResults) {
                    var ruleResult = ruleResults[i];
                    // Don't display lower-impact suggestions.
                    if (ruleResult.ruleImpact < 3.0)
                        continue;
                    results.push({name: ruleResult.localizedRuleName,
                        impact: ruleResult.ruleImpact});
                }
                results.sort(sortByImpact);
                var ul = document.createElement('ul');
                for (var i = 0, len = results.length; i < len; ++i) {
                    var r = document.createElement('li');
                    r.innerHTML = results[i].name;
                    ul.insertBefore(r, null);
                }
                if (ul.hasChildNodes()) {
                    document.body.insertBefore(ul, null);
                } else {
                    var div = document.createElement('div');
                    div.innerHTML = 'No high impact suggestions. Good job!';
                    document.body.insertBefore(div, null);
                }
            };

            // Helper function that sorts results in order of impact.
            function sortByImpact(a, b) {
                return b.impact - a.impact;
            }
        </script>

        <script>
            var RESOURCE_TYPE_INFO = [
                {label: 'JavaScript', field: 'javascriptResponseBytes', color: 'e2192c'},
                {label: 'Images', field: 'imageResponseBytes', color: 'f3ed4a'},
                {label: 'CSS', field: 'cssResponseBytes', color: 'ff7008'},
                {label: 'HTML', field: 'htmlResponseBytes', color: '43c121'},
                {label: 'Flash', field: 'flashResponseBytes', color: 'f8ce44'},
                {label: 'Text', field: 'textResponseBytes', color: 'ad6bc5'},
                {label: 'Other', field: 'otherResponseBytes', color: '1051e8'}
            ];

            callbacks.displayResourceSizeBreakdown = function(result) {
                var stats = result.pageStats;
                var labels = [];
                var data = [];
                var colors = [];
                var totalBytes = 0;
                var largestSingleCategory = 0;
                for (var i = 0, len = RESOURCE_TYPE_INFO.length; i < len; ++i) {
                    var label = RESOURCE_TYPE_INFO[i].label;
                    var field = RESOURCE_TYPE_INFO[i].field;
                    var color = RESOURCE_TYPE_INFO[i].color;
                    if (field in stats) {
                        var val = Number(stats[field]);
                        totalBytes += val;
                        if (val > largestSingleCategory)
                            largestSingleCategory = val;
                        labels.push(label);
                        data.push(val);
                        colors.push(color);
                    }
                }
                // Construct the query to send to the Google Chart Tools.
                var query = [
                    'chs=300x140',
                    'cht=p3',
                    'chts=' + ['000000', 16].join(','),
                    'chco=' + colors.join('|'),
                    'chd=t:' + data.join(','),
                    'chdl=' + labels.join('|'),
                    'chdls=000000,14',
                    'chp=1.6',
                    'chds=0,' + largestSingleCategory
                ].join('&');
                var i = document.createElement('img');
                i.src = 'http://chart.apis.google.com/chart?' + query;
                document.body.insertBefore(i, null);
            };
        </script>

    </head>
    <body onload="runPagespeed();">
        <div>Java-Buddy: Google Page Speed Insights test</div>
        <p id="testedurl">
    </body>

</html>



Main JavaFX code.
package javafx_pagespeedinsights;

import java.net.URL;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebEvent;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

/**
 *
 * @web http://java-buddy.blogspot.com/
 */
public class JavaFX_PageSpeedInsights extends Application {

    private Scene scene;
    MyBrowser myBrowser;

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("java-buddy.blogspot.com");

        myBrowser = new MyBrowser();
        scene = new Scene(myBrowser, 640, 500);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    class MyBrowser extends Region {

        HBox toolbar;
        WebView webView = new WebView();
        WebEngine webEngine = webView.getEngine();

        public MyBrowser() {

            final URL PageSpeedTest = getClass().getResource("PageSpeedTest.html");
            webEngine.load(PageSpeedTest.toExternalForm());
            
            webEngine.setOnAlert(new EventHandler<WebEvent<String>>(){

                @Override
                public void handle(WebEvent<String> t) {
                    System.out.println(t.getData());
                }

            });

            getChildren().add(webView);

        }
    }
}


1 comment:

  1. Thank you for great examle, wasn't able to find one good and clean example over the internet besides this one. Thanks.

    ReplyDelete