Plotlyのhoverboxがモバイル環境で消えない問題とその回避策の巻
はじめに
Plotlyを使ってインタラクティブなチャートをモバイル端末で表示するときに、データポイントをタップすることでhoverboxが開いて設定しておいたtextの内容を表示できます。
でもこのhoverboxが、plotの内容を更新して他のチャートに切り替えたときに消えずに残ってしまいます。
一応、他の場所をタップすると消えるのですが、なんか気持ち悪い。チャートを切り替えた時に一緒に消えて欲しいのよ。。。
で、いろいろ試行錯誤した結果、HTMLにJavaScriptを追加することで解決できました、という話です。
<対応前:こんな感じでhoverboxが残る>
<対応後:チャートを切り替えた時にhoverboxは消える>
実施環境
Plotlyバージョン: plotly-3.0.1.min.js
これを動作させるHTMLファイルを作成し、ブラウザでHTMLファイルを開いてPlotlyのチャートを表示するというシチュエーションです。
原因
hoverboxが表示されるのは、
HTMLの記述において
<g class=”hoverlayer”></g>
の部分で、hoverboxが表示されるときにhoverlayerクラスの子にhoverboxの内容が挿入されます。
これが残ったままになることが原因のようでした。
対策
- チャートの更新(
plotly_update
)イベントにイベントリスナーを仕掛ける plotly_update
イベントが発火したらhoverlayer内のHTMLを空にしてhover情報をリセットする
メモ
plotly_update
は、Plotly.js でPlotly.update()
などを使ってグラフのデータやレイアウトが更新されたときに発火するイベントです。- 他のイベント(
plotly_relayout
やplotly_restyle
)でも使えるかも(試してないです)。
実装
具体的には、HTMLにおけるscriptタグ内の、Plotlyがプロットを作成する部分であるこのコードを、、、
Plotly.newPlot('plot', [graph1, graph2], layout)
こうする
Plotly.newPlot('plot', [graph1, graph2], layout).then(() => {
const plotElem = document.getElementById('plot');
plotElem.on('plotly_update', function () {
const hoverLayer = plotElem.querySelector('.hoverlayer');
if (hoverLayer) hoverLayer.innerHTML = '';
});
});
これで、冒頭の動画のように、foverboxがチャートの切り替えで消えるようになりました。
ちなみに今回のサンプルのHTMLファイルの中身の全体はこうです
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>
</head>
<body>
<div id="plot"></div>
<script>
const graph1 = {
x: [1, 2, 3],
y: [1, 2, 1],
mode: 'markers',
type: 'scatter',
name: 'Graph 1',
marker: { color: 'blue' },
text: [
'A: Point 1<br>X=1, Y=1',
'A: Point 2<br>X=2, Y=2',
'A: Point 3<br>X=3, Y=1'
],
hoverinfo: 'text',
visible: true
};
const graph2 = {
x: [1, 2, 3],
y: [3, 2, 4],
mode: 'markers',
type: 'scatter',
name: 'Graph 2',
marker: { color: 'red' },
text: [
'B: Point 1<br>X=1, Y=3',
'B: Point 2<br>X=2, Y=2',
'B: Point 3<br>X=3, Y=4'
],
hoverinfo: 'text',
visible: false
};
const layout = {
title: {
text: 'Graph 1',
x: 0.03,
xanchor: 'left',
font: { size: 18, color: 'black' }
},
updatemenus: [
{
type: 'buttons',
direction: 'down',
showactive: true,
x: -0.1,
xanchor: 'left',
y: 1.0,
yanchor: 'top',
buttons: [
{
label: 'Graph 1',
method: 'update',
args: [
{ visible: [true, false] },
{ title: 'Graph 1' }
]
},
{
label: 'Graph 2',
method: 'update',
args: [
{ visible: [false, true] },
{ title: 'Graph 2' }
]
}
]
}
]
};
Plotly.newPlot('plot', [graph1, graph2], layout).then(() => {
const plotElem = document.getElementById('plot');
plotElem.on('plotly_update', function () {
const hoverLayer = plotElem.querySelector('.hoverlayer');
if (hoverLayer) hoverLayer.innerHTML = '';
});
});
</script>
</body>
</html>
試してみる
次のリンクをクリックしたら直接チャートが開きます(そのはず)
というわけで、冒頭の動画で示したように修正することができました。
なお、こちらのリンク先にbefore afterのHTMLファイルを格納してあります。
GitHub repo: plotly-mobile-hover-demo
おわりに
モバイルでのPlotlyのhoverboxが残ってしまう問題を、Javascriptのイベントリスナーを使ってHTML内のhoverlayerをクリアすることで解決したというお話でした。おしまい。