web-dev-qa-db-ja.com

NVD3チャートが非表示のタブで正しくレンダリングされない

表示しているタブに応じて一度に1つずつ表示される、多くのグラフを含むページを作成しています。

最初にアクティブなタブのグラフは正しくレンダリングされます。ただし、別のタブをクリックすると、グラフが正しくレンダリングされません。

おそらくこれは、非表示のフィールドが表示されるまでディメンションがないためです。実際、ウィンドウのサイズを変更すると、グラフはその比率を修正し、使用可能な幅を満たすようにレンダリングします。

Cssを使用してグラフのサイズを明示的に定義することでこの問題を修正できますが、これはグラフの応答性の側面を無効にします。

ウィンドウのサイズが変更されたときにアクティブになる同じNVD3イベントをトリガーする方法を誰かに教えてもらえますか?そうすれば、それを新しいタブの選択にバインドでき、うまくいけばレンダリングの問題を解決できます。

18
metaColin

必要なサイズ変更イベントをトリガーする方法を見つけました。私の場合、タブはブートストラップによって駆動されます。そのため、bootstrap show tabイベントを変更して、ページサイズ変更イベントもトリガーするようにしました。これは少し間接的ですが、作業は完了します。

jQuery('#myTab a').click(function (e) {
    e.preventDefault()
    jQuery(this).tab('show')
    jQuery(window).trigger('resize'); // Added this line to force NVD3 to redraw the chart
})
12
metaColin

私は同じ問題(複数のタブのグラフ)を抱えていましたが、これが私が仕事に取り掛かることができた唯一のことです。

$(function () {
    $(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function (e) {
        window.dispatchEvent(new Event('resize'));
    });
});

ただし、アクティブなタブ(表示)または選択されていないタブ(非表示)のどちらにあるかに関係なく、すべてのグラフが再レンダリングされているように感じます。

アクティブなチャートのみがサイズ変更/再描画されるようにする方法を知っている人はいますか?

16

このJavaScriptを追加するだけです。

$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
  window.dispatchEvent(new Event('resize'));
})

hidden.bs.tabは、Bootstrap docsに従って、新しいタブが表示された後に発生するイベントです。このコードは、タブが変更されるたびにサイズ変更イベントを発生させます。

8
nostromo

新しい回答の理由

バニラJavascriptは2018の多くの人々に必要です。今日存在する多くのフレームワークとJavascriptライブラリは、jQueryではうまく機能しません。昔々、jQueryソリューションですべてのJavascriptの問題に答えることは受け入れられましたが、もはや実現可能ではありません。

問題

C3.jsまたはD3.jsグラフをロードするときに、ページのロード中にビューポートがサイトにアクティブにない場合、グラフは正しくレンダリングされません。

  1. URLを入力する場合は、新しいタブを開き、ページが読み込まれた後に戻ります。

  2. グラフが表示されているページを更新する場合は、ブラウザを最小化し、ページが読み込まれた後に開いてください。

  3. グラフを更新するかページに移動する場合は、スワイプしてコンピューターの新しいウィンドウに移動します。次に、グラフが読み込まれた後、グラフのあるページに戻ります。

これらすべての場合において、C3.js /D3.jsグラフは正しくレンダリングされません。通常、空白のキャンバスが表示されます。したがって、棒グラフを期待している場合は、棒が描画されていないキャンバスが表示されます。

背景

この質問の回答を見たことがありますが、[〜#〜] not [〜#〜] jQueryを使用する回答が必要でした。すべてがjQueryで修正できない時代に達したので、この質問に対するVanillaJavascriptの回答を提供するのが適切だと思いました。

私のチームは、ページを更新してスワイプするか最小化すると、C3.js /D3.jsグラフが読み込まれないという問題に直面しました。基本的に、ページにとどまらず、読み込みが完了するまでサイトに保持していた場合、ページのサイズを再度変更するまでグラフは表示されません。これはC3.js/D3.jsを使用するすべての人に発生する問題であることを私は知っていますが、私たちは特にSalesforceでLightningを使用しています。

回答

私たちの修正は、チャートを初期化するコントローラー関数にこれを追加することでした。スタックに関係なく、誰でもこれを作成する関数で使用して、C3.js /D3.jsグラフを初期化できます。これはSalesforceに依存しませんが、Salesforceでこの問題に直面している場合は実際に機能します。

document.addEventListener('visibilitychange', () => {
   console.log(document.visibilityState);
   window.dispatchEvent(new Event('resize'));
});
5
wuno

私は同じ問題に直面していました。 ng-showを使用してdivを非表示にしました。 ng-showをng-ifに置き換えると、期待される動作で描かれたグラフを見ることができます。説明:

  1. Ng-showまたはng-hideを使用してdivを非表示にすると、それが変更されるだけですdisplay propertyが、divはdomになります。

  2. ng-ifを使用すると、divがdomから削除され、再びdomに追加されるため、内部的にはnvd3グラフに対しても再描画操作が実行されます。したがって、押しつぶされたグラフではなく、正しいグラフが表示されます。

4
samyak bhalerao

より効率的なアプローチは、chart.update()メソッドを使用することです。

var chart_x = nv.models.somechart()
var chart_y = nv.models.somechart()

.....チャートを表示

jQuery('#myTab a').click(function (e) {
    e.preventDefault()
    jQuery(this).tab('show')
    if(jQuery(this)...something === '..x..')
      chart_x.update(); //CALL THE UPDATE
    else ...  

})

0
Bogdan

通常、再描画をトリガーするイベントはウィンドウresizeイベントです。NVD3はこのためにカスタムイベントを使用しません。ただし、これは自分で制御できます。通常の定義は

nv.utils.windowResize(function() { d3.select('#chart svg').call(chart); });

(ここで、「#chart」はグラフを含む要素です)。別のイベントでコードをトリガーしたり、タブを変更したときにコードを明示的に再描画したりすることを妨げるものは何もありません。

0
Lars Kotthoff