前提
- [Chart.js][JavaScript]再生数グラフ付きプレーヤー開発・再生位置カーソルを追加したい
https://teratail.com/questions/360634
- [Chart.js][JavaScript] CSSで描画した円カーソルをChart.jsのグラフ項目のトップに表示させたい
https://teratail.com/questions/360753
- [Chart.js][JavaScript] グラフ部分をクリックして対応の再生位置に遷移させたい、再生バー動かしたらカーソルも移動させたい
https://teratail.com/questions/361574
実現したいこと
- プレーヤーシークバーの移動(再生ボタン押下、シークバードラッグなど)に応じてグラフ頂点のカーソルを連動させたい
カーソルというのは画像の赤点を指しています。グラフ項目の頂点をマウスオーバーやクリックに応じて移動するイメージです。
プレーヤーの現在再生時間を取得し、グラフ項目の一番近い部分にカーソルを描画するかと思いますが、画像を例とし、以下の流れを想定しています。
- プレーヤーの現在再生時間を取得(17秒)
- 現在再生時間÷全体再生時間=再生割合を算出(17秒÷30秒=56%)
- グラフ項目数×再生割合=移動すべき項目を算出(今回は四捨五入で30個×56%=17)
- 対象のグラフ項目トップにカーソル描画(17番目のグラフ項目)
また前回の質問でも回答者様より以下の助言いただきました。
・Barチャートの各要素の高さを取得する方法
・リスト特定のindexの要素のBarの頂点位置にカーソルを描画/更新する方法 または
・特定の要素のツールチップ位置にカーソルを固定表示する方法
が必要になりそうです。
このうち現在再生時間(currentTime)、全体再生時間(duration)、グラフの順番(index)は取得できました。対象グラフ項目の高さもそれらしい(element.height)のを取得できましたが、それ以降の工程、つまり対象グラフ項目のトップにカーソルを描画するロジックが自分の力だけではなかなか思いつきません。皆様のご協力をお待ちしております。
追記:
2021.10.12 videoタグ仕様を見るとseekingイベントというのがあるので、ここでseekingイベントハンドラを記載し、そこでdrawCursor関数と同様の処理を書けばいいのではと考えていますがいかがでしょうか。
ソースコード
JavaScript
1<html> 2 <head > 3 <meta http-equiv="Content-Style-Type" content="text/html"> 4 <title>Chart.js Sample</title> 5 <style type="text/css"> 6 #wrapper { 7 position: relative; 8 padding-bottom: 60%; 9 width: 100%; 10 } 11 12 #video { 13 position: absolute; 14 width: 100%; 15 } 16 17 #chart { 18 z-index: 3; 19 position: absolute; 20 padding-top: 60%; 21 width: 100%; 22 height: 85%; 23 bottom: 100px; 24 } 25 26 #cursor { 27 z-index: 4; 28 position: absolute; 29 width: 20px; 30 height: 20px; 31 border-radius: 50%; 32 background: red; 33 } 34 </style> 35 </head> 36 <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script> 37 <body> 38 <div id="wrapper"> 39 <video id="video" src="file_example_MP4_1280_10MG.mp4" type="video/mp4" controls></video> 40 <div id="chart"> 41 <canvas id="myChart"></canvas> 42 <script> 43 var data_labels = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 44 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 45 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 ] 46 var data_sets = [ 35, 25, 33, 15, 18, 6, 20, 39, 12, 8, 47 6, 15, 35, 30, 23, 10, 8, 5, 11, 30, 48 35, 39, 40, 41, 32, 20, 12, 9, 3, 1 ] 49 var canvas = document.getElementById( 'myChart' ); 50 var context = canvas.getContext('2d'); 51 var graph = { 52 type: 'bar', 53 data: { 54 labels: data_labels, 55 datasets: [{ 56 label: 'Views', 57 data: data_sets, 58 backgroundColor: [ 59 'rgba(255, 255, 0, 0.2)' 60 ], 61 barPercentage: 1, 62 categoryPercentage: 1, 63 }] 64 }, 65 options: { 66 title: { 67 display: false, 68 }, 69 responsive: true, 70 legend: { 71 display: false, 72 }, 73 scales: { 74 x: { 75 display: false, 76 }, 77 y: { 78 display: false, 79 } 80 }, 81 plugins: { 82 legend: { 83 display: false, 84 }, 85 tooltip: { 86 enabled: false, 87 external: drawCursor, 88 } 89 }, 90 events: ['click'], 91 onClick: (e) => { 92 // クリックした要素の取得 93 var ele = myGraph.getElementsAtEventForMode( 94 e, 'index', { intersect: false }, false); 95 //デバッグ用・何番目の項目かを表示、高さを表示 96 console.log(ele); 97 console.log("Index: " + ele[0].index); 98 console.log("Height: " + ele[0].element.height); 99 100 var eleIndex = ele[0].index; 101 var eleLength = data_sets.length; 102 // 再生位置更新 103 var v = document.getElementById("video"); 104 var duration = v.duration; 105 v.currentTime = duration * eleIndex / eleLength; 106 } 107 } 108 }; 109 var myGraph = new Chart( canvas, graph ); 110 111 function drawCursor(context) { 112 console.log(context); 113 //ツールチップ要素 114 var tooltipEl = document.getElementById('chartjs-tooltip'); 115 116 //div要素を生成 117 if (!tooltipEl) { 118 tooltipEl = document.createElement('div'); 119 tooltipEl.id = 'chartjs-tooltip'; 120 121 var canvas_ = document.createElement("canvas"); 122 canvas_.height = 30; 123 canvas_.width = 30; 124 tooltipEl.appendChild(canvas_); 125 document.body.appendChild(tooltipEl); 126 127 context_ = canvas_.getContext('2d'); 128 context_.beginPath(); 129 context_.arc( 130 10, 131 10, 132 10, 133 0 * Math.PI / 180, 134 360 * Math.PI / 180 135 ); 136 context_.fillStyle = "red"; 137 context_.fill(); 138 canvas_.id = "cursor"; 139 140 } 141 142 //ツールチップがない場合は非表示 143 var tooltipModel = context.tooltip; 144 if (tooltipModel.opacity === 0) { 145 tooltipEl.style.opacity = 0; 146 return; 147 } 148 // グラフ内部にカーソルがなくてもツールチップがX軸方向に動くようにするためには、以下2行の設定が必要。 149 tooltipModel.options.intersect = false; 150 tooltipModel.options.mode = 'x'; 151 152 var position = context.chart.canvas.getBoundingClientRect(); 153 var bodyFont = Chart.helpers.toFont(tooltipModel.options.bodyFont); 154 155 tooltipEl.style.opacity = 1; 156 tooltipEl.style.position = 'absolute'; 157 tooltipEl.style.left = position.left + window.pageXOffset + tooltipModel.caretX -10+ 'px'; 158 tooltipEl.style.top = position.top + window.pageYOffset + tooltipModel.caretY -10+ 'px'; 159 tooltipEl.style.font = bodyFont.string; 160 tooltipEl.style.padding = tooltipModel.padding + 'px ' + tooltipModel.padding + 'px'; 161 tooltipEl.style.pointerEvents = 'none'; 162 163 //再生箇所をDiv:textに表示したい 164 var video_ = document.querySelector('video'); 165 video_.addEventListener("timeupdate", (e) => { 166 var currentTime_ = video_.currentTime; 167 //デバッグ:現在の再生位置を取得 168 console.log("CurrentTime: " + currentTime_); 169 console.log(e); 170 }); 171 video_.addEventListener("seeking", (e) => { 172 var currentTime_ = video_.currentTime; 173 } 174 </script> 175 </div> 176 </div> 177 </body> 178</html>
補足情報
- Chart.js 3.5.1 最新版
- 使用MP4ファイル:https://file-examples.com/index.php/sample-video-files/sample-mp4-files/
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2021/10/15 10:10
退会済みユーザー
2022/03/07 08:33
退会済みユーザー
2022/03/07 08:34