2

StackOverflow 評価グラフに非常によく似たフロート グラフを作成しています。データの鳥瞰的なレベルを示す小さなグラフがあり、範囲を選択してズームして大きなグラフに表示できます。いずれかのグラフをホバーすると、凡例のテキストが更新され、その x 位置の値が反映されます。

私が遭遇している2つの問題があり、コンソールなどにエラーがまったく見つかりません...

1: 「ズーマー」グラフで範囲を選択すると、大きい方の「詳細」グラフは適切に拡大されますが、x 値をホバーしたときに凡例テキストを更新するコードが機能しなくなります。ポイント アイテムのマウス オーバー (ツールチップが表示される) は引き続き機能し、2 つのコード ビットは同じイベント内にあります。変。

2: ズームインすると、日付の形式が乱れます。指定されているにもかかわらず、日付はタイムスタンプに戻さtimeformatれます (実際には、ズームが行われる前の最初のプロットで機能します)。


実際の問題を示す短いスクリーンキャストを記録しました。

http://www.screenr.com/KUX8


日付/時刻のフォーマットの問題を示す JSFiddle をセットアップしました。何らかの理由で、その環境では、ホバリング イベントが期待どおりに機能していません。

http://jsfiddle.net/Kzg3r/2/


これら2つの問題を引き起こす何かが欠けていますか?


//doPlot is originally called where ranges=null. This plots the entire universe
//of data on both charts. Once a range is selected, this is called again with
//ranges


var plot=null;
var plot2=null;
var updateLegendTimeout = null;
var latestPosition = null;   
var datasets=null;
var currRange=null;

function doPlot(ranges){
    currRange=ranges;

    clearTimeout(updateLegendTimeout);
    updateLegendTimeout = null;

    var options = { //Options for large graph
        lines: { show: true },
        points: { show: true },
        grid: { hoverable: true, clickable: false, autoHighlight: false, backgroundColor: { colors: ["#fff", "#eee"] }, markings: weekendAreas   },
        xaxis: {mode: 'time', timeformat: "%m/%d", minTickSize: [1, "day"]},
        crosshair: { mode: "x" },
        legend: {
            show: true,
            container: $('#legend'),
            noColumns: 2
        }
    };

    var options2 = {  //options for small zoomer graph
        lines: { show: true },
        points: { show: false },
        grid: { hoverable: true, clickable: true, autoHighlight: false, backgroundColor: { colors: ["#fff", "#eee"] }, markings: weekendAreas   },
        xaxis: {mode: 'time', timeformat: "%m/%d", minTickSize: [1, "month"]},
        crosshair: { mode: "x" },
        selection: { mode: "x" },
        legend: { show: false }
    };    


    if (currRange){ //if there is a range specified, extend options to include it.
        options = $.extend(options, {
            xaxis: { 
                min: currRange.xaxis.from, 
                max: currRange.xaxis.to 
            }
        });

    }

    //Plot Large Graph with (or without) given range
    plot = $.plot($("#placeholder"), datasets,options);


    //plot the zoomer graph, only if it is null (it is set to null before ajax request for new chart)
    if (!plot2) { 
        plot2 = $.plot($("#zoomer"), datasets, options2);


        $("#zoomer").unbind("plotselected").bind("plotselected", function (event, ranges) {

            //unbind/re-bind plotselected event to zoom in when a range is selected
            doPlot(ranges);

        }).unbind("plothover").bind("plothover",  function (event, pos, item) {

            //unbind/re-bind plothover event to to show tooltips and to change legend values
            latestPosition = pos;
            if (!updateLegendTimeout)
                updateLegendTimeout = setTimeout(function(){
                    updateLegend(plot2);
                }, 50);

            if (item) {
                if (previousPoint != item.dataIndex) {
                    previousPoint = item.dataIndex;

                    $("#tooltip").remove();
                    var x = item.datapoint[0].toFixed(2),
                        y = item.datapoint[1].toFixed(2);
                    var text = item.series.label.split(' = ');

                    showTooltip(item.pageX, item.pageY,
                                text[0] + ' ('+y+')');
                }
            }
            else {
                $("#tooltip").remove();
                previousPoint = null;            
            }
        });         
    }

    doBinds();          
}


function doBinds(){
    $("#placeholder").unbind("plothover").bind("plothover",  function (event, pos, item) {
        latestPosition = pos;
        if (!updateLegendTimeout)
            updateLegendTimeout = setTimeout(function(){
                updateLegend(plot);
            }, 50);

        if (item) {
            if (previousPoint != item.dataIndex) {
                previousPoint = item.dataIndex;

                $("#tooltip").remove();
                var x = item.datapoint[0].toFixed(2),
                    y = item.datapoint[1].toFixed(2);
                var text = item.series.label.split(' = ');

                showTooltip(item.pageX, item.pageY,
                            text[0] + ' ('+y+')');
            }
        }
        else {
            $("#tooltip").remove();
            previousPoint = null;            
        }    
    });  
}
4

1 に答える 1

3

x 軸の目盛りの問題は、範囲が選択されている場合に doPlot 関数でプロット オプションを拡張する方法に関係しています。ディープ コピーを実行するには、最初の引数として `true を指定して jQuery.extend を呼び出す必要があります。それ以外の場合、オプション オブジェクトを x 軸の最小値と最大値で拡張すると、モードが時間に設定された x 軸オブジェクトが上書きされます。そのビットをこれに置き換えると、その問題が修正されます。

    if (currRange){ //if there is a range specified, extend options to include it.
        options = $.extend(true, options, {
            xaxis: { 
                min: currRange.xaxis.from, 
                max: currRange.xaxis.to 
            }
        });

    }

編集:

したがって、チャートが再描画されると、凡例項目が削除され、新しい項目が追加されるため、最初の問題が発生します。ドキュメントの準備ができたときに元の凡例ラベルへの参照を保存しますが、グラフが再描画されると、これらは DOM に関連付けられなくなります。新しく作成された凡例ラベルではなく、これらの切り離された要素のラベルを更新しています。次のように凡例を更新するときに、凡例コレクションを再初期化してみてください。

//THIS IS MOST LIKELY WHERE THE PROBLEM IS OCCURRING!!!!
function updateLegend(thePlot) {
    legends = $('.legendLabel');   
    clearTimeout(updateLegendTimeout);
    updateLegendTimeout = null;

    var pos = latestPosition;

    var axes = thePlot.getAxes();
    if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
        pos.y < axes.yaxis.min || pos.y > axes.yaxis.max)
        return;

    var i, j, dataset = thePlot.getData();
    for (i = 0; i < dataset.length; ++i) {
        var series = dataset[i];

        // find the nearest points, x-wise
        for (j = 0; j < series.data.length; ++j)
            if (series.data[j][0] > pos.x)
                break;

        // now interpolate
        var y, p1 = series.data[j - 1], p2 = series.data[j];
        if (p1 == null)
            y = p2[1];
        else if (p2 == null)
            y = p1[1];
        else
            y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);

        legends.eq(i).text(series.label.replace(/=.*/, "= " + y.toFixed(2)));
    }
}
于 2012-05-25T20:20:07.967 に答える