Using Flot's Bar Graph in an Android WebView with Highlighting

 

The issue is unhighlighting bars which are no longer selected in a bar graph plotted by flot in a WebView on Android. Got no other issues drawing the actual graphs (which look beautiful for something so simple btw). I am not extremely knowledgeable in terms of javascript and web design/development but it seems little should have been needed, if it would just work!! :( I believe I'm following the Flot API correctly, if not someone please scream and yell at me.

Hoping someone has done this before, but if not I've got the minimal necessary code to poke at your droids if inquiring minds would like to test. I've tested on two Nexus Ones (both 2.2.1), and have tried targeting with Andriod 1.5 and 2.2 SDKs (my intention is to target 1.5 if possible). I've been attempting to hack away at this for far to long on my own now.

What happens:
1. Graph loads fine with bars. All bars unhighlighted.
2. Select a bar in graph, gets highlighted fine (and a tooltip is placed).
3. Select a different bar in graph, old bar is unhighlighted, old tooltip removed, new bar highlighted and tooltip placed (still no problems).
4. Click in the vast darkness of the graph which should then unhighlight the last bar... but it doesn't.

I've tried disabling flot's autohighlight and manually doing it as well to no avail. Looking into flot itself and only getting down to drawOverlay() where the issue seems to begin... An even more disturbing bug(?) appears if the fill bar option is enabled in the graph, but I'd rather just forget about that for now. I've tried with the latest version of flot from their svn (r290), but made no different from last public release (v0.6). As a complete guess I'm thinking it's an issue with WebKit's javascript implementation (or something specific to Nexus Ones, which wouldn't be so bad), but if there is any ugly hack to just get it to work I'm all ears.

I've thrown the graph data directly into the html/js, rather than deal with showing all the code involved in the Java->javascript handler and callbacks.

The html is placed in 'assets/stats_graph.html' with jquery.js and jquery.flot.js (this will load just fine on its own in firefox):

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
  <head> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
    <script src="jquery.js"></script> 
    <script src="jquery.flot.js"></script> 
 
    <script id="source" language="javascript" type="text/javascript"> 
        var lastItem = null; 
        var plot = null; 
 
        $(document).ready(function () { 
            //window.testhandler.loadGraph(); 
 
            // bind plotclick here 
            $("#graphHolder").bind("plotclick", function (event, pos, item) { 
                if (item) { 
                    var lastPoint = null; 
                    if (lastItem != null) 
                        lastPoint = lastItem.datapoint; 
                    if (!pointEquals(lastPoint, item.datapoint)) { 
                        //if (lastItem != null) 
                        //    plot.unhighlight(lastItem.series, lastItem.datapoint); 
                        lastItem = item; 
 
                        $("#tooltip").remove(); 
                        //plot.highlight(item.series, item.datapoint);      
                        showTooltip(item.pageX, item.pageY, item.datapoint[1]); 
                    } 
                } else if (lastItem != null) { 
                    plot.unhighlight(lastItem.series, lastItem.datapoint); // not unhighlighting anything 
                    //plot.unhighlight(); // doesn't work either, supposed to unhighlight everything 
                    lastItem = null; 
 
                    $("#tooltip").remove();      
                } 
            }); 
 
            GotGraph(); 
        }); 
 
        /** 
         * Show a tooltip above bar in graph 
         * @param {int} x Left coordinate of div  
         * @param {int} y Top coordinate of div 
         * @param {String} contents text to place in div 
         */ 
        function showTooltip(x, y, contents) { 
            $('<div id="tooltip">' + contents + '</div>').css( { 
                position: 'absolute', 
                display: 'none', 
                top: y, 
                left: x, 
                border: '1px solid #fdd', 
                padding: '2px', 
                'background-color': '#fee', 
                opacity: 0.80 
            }).appendTo("body").fadeIn(200); 
        } 
 
        /** 
         * Draw the graph. This is a callback which will be called by Java 
         *  
         * @param {Object} seriesData 
         * @param {Object} seriesOptions 
         */  
        function GotGraph() { //seriesData, seriesOptions) { 
            var seriesData = [{ 
                "bars":{"lineWidth":2,"show":true,"barWidth":86400000,"align":"center","fill":false}, 
                "data":[[1288569600000,10],[1288656000000,5],[1288742400000,12],[1288828800000,20],[1288915200000,14],[1289001600000,3],[1289174400000,22],[1289260800000,20],[1289347200000,10],[1289433600000,5],[1289520000000,12],[1289606400000,20],[1289692800000,14],[1289779200000,35]]}]; 
            var seriesOptions = { 
                "xaxis":{"twelveHourClock":false,"minTickSize":[1,"day"],"tickSize":[1,"day"],"timeformat":"%d","mode":"time"}, 
                "yaxis":{"min":0}, 
                "grid":{"clickable":true,"autoHighlight":true,"hoverable":false}}; 
 
            plot = $.plot($("#graphHolder"), seriesData, seriesOptions); 
        } 
 
        function pointEquals(point1, point2) { 
            if (point1 != null && point2 != null && 
                typeof(point1) == typeof(point2) && 
                point1.length == point2.length) { 
                var i; 
                for (i=0;i<point1.length;i++) { 
                    if (point1[i] != point2[i]) 
                        return false; 
                } 
                return true; 
            } 
            return false; 
        } 
    </script> 
  </head> 
  <body> 
    <div id="graphHolder" STYLE="height:200px;width:400px"></div> 
  </body> 
</html> 

The minimal amount of code necessary in onCreate in startup activity:

@Override 
public void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 
 
    WebView mytestView = new WebView(this); 
    mytestView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); 
    setContentView(mytestView); 
 
    mytestView.setBackgroundColor(0); 
    mytestView.getSettings().setJavaScriptEnabled(true); 
    mytestView.setClickable(true); 
    mytestView.setFocusable(false); 
    mytestView.setFocusableInTouchMode(false); 
    mytestView.loadUrl("file:///android_asset/stats_graph.html"); 
}
link | improve this question

71% accept rate
 
Hey, i tried running your code and it is working pretty fine.. A point mentioned by you: if you click in the dark space which should then unhighlight the last bar, it is working perfectly fine for me. FYI: i am using flot0.6 lib. plus is there a way i can set the graph value from java code? –  mudit Jan 12 '11 at 6:16
 
Interesting, what phone do you have and what OS version is it running? If it turns out it's just my Nexus Ones I don't feel that bad then, guess I'll just leave it be. –  Nicholi Jan 12 '11 at 20:34
 
And yes you can easily modify the entire graph data+options from Java. Essentially all you need to do is create a new class/interface to act as a handler and link it to the WebView with addJavascriptInterface(). You can then call back to the Java code from js with the interface, and you can call specific js functions using the WebView's (after it's been loaded once) loadUrl("javascript:functionName(params)") and pass everything as JSONObjects/Arrays. This article has the rest of the details: rapidandroid.org/wiki/Graphing –  Nicholi Jan 12 '11 at 20:37
 
I think I've found the answer to my issue (maybe mudit was testing on the emu, which for some things is nothing like what the phones actually do). Flot draws using two canvases and I guess when using jquery's appendTo/remove features a third canvas is being utilized, which freaks out when there are no elements on it (tooltip is removed) and somehow messes up drawing everything else. My quick fix is to use flot's overlaydraw hook and remove the tooltip on a timer. Real solution would be to add all my tooltip drawing with the hooks using flot's overlay canvas. Will post back when I try that out. –  Nicholi Jan 18 '11 at 1:07
Was this post useful to you?     

Didn't tried, but looking at the code, calling unhighlight() without args should do.

The source code of my version, for reference:

     function unhighlight(s, point) { 
        if (s == null && point == null) { 
            highlights = []; 
            triggerRedrawOverlay(); 
        } 
 
        if (typeof s == "number") 
            s = series[s]; 
 
        if (typeof point == "number") 
            point = s.data[point]; 
 
        var i = indexOfHighlight(s, point); 
        if (i != -1) { 
            highlights.splice(i, 1); 
 
            triggerRedrawOverlay(); 
        } 
    } 
link | improve this answer
 
Yeah calling unhighlight() doesn't work, that is in the example code (albeit commented out). Nor does calling unhighlight and specifying the element. I haven't gotten around to trying this again since 2.3, or finding out if it is only the Nexus One even. –  Nicholi Apr 14 '11 at 0:46
 
I'd be interested to know if unlight() does work in your PC browser. If it really is a Nexus One bug that'd piss me off pretty much. –  tacone Apr 14 '11 at 11:56
http://stackoverflow.com/questions/4664369/using-flots-bar-graph-in-an-android-webview-with-highlighting
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值