概要
amChartsのDate Based Dataを使用しグラフを作成します。
こちらのグラフは起動時に全体を表示し、”最終日からある割合”の日付をズームして表示します。(かっこいい)
Demo source
この**”最終日からある割合”を”直近の1週間”**に変更していきたいとおもいます。(上のDemo sourceのgifでは直近の8日にプロットされた値が表示されてますね)
##作成する前提
amChartsがCDNで読み込めている
参考文献amcharts 4 Demos を使ってグラフを作成(amChartsの導入方法が記載されています)
使用するグラフの種類:Date Based Data
使用するモデル:Railsにて不連続な間隔(日付など)で投稿された値をamChartsを使って折れ線グラフを作成する。において作成した体重管理アプリをモデルに作成します。コントローラーファイルなどの記述はこちらを参考にしてください。
##編集するファイル
・ビューファイル
###ビューファイル(Demo source)
まずは、Demo sourceがどういう構造になっているか見てみましょう。
<!-- Styles -->
<style>
#chartdiv {
width: 100%;
height: 500px;
}
</style>
<!-- Resources -->
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
<!-- Chart code -->
<script>
am4core.ready(function() {
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);
// Add data
chart.data = [{
"date": "2012-07-27",
"value": 13
}, {
"date": "2012-07-28",
"value": 11
}, {
"date": "2012-07-29",
"value": 15
}, {
//~省略~
"date": "2013-01-30",
"value": 81
}];
// Set input format for the dates
chart.dateFormatter.inputDateFormat = "yyyy-MM-dd";
// Create axes
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
// Create series
var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.valueY = "value";
series.dataFields.dateX = "date";
series.tooltipText = "{value}"
series.strokeWidth = 2;
series.minBulletDistance = 15;
// Drop-shaped tooltips
series.tooltip.background.cornerRadius = 20;
series.tooltip.background.strokeOpacity = 0;
series.tooltip.pointerOrientation = "vertical";
series.tooltip.label.minWidth = 40;
series.tooltip.label.minHeight = 40;
series.tooltip.label.textAlign = "middle";
series.tooltip.label.textValign = "middle";
// Make bullets grow on hover
var bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.circle.strokeWidth = 2;
bullet.circle.radius = 4;
bullet.circle.fill = am4core.color("#fff");
var bullethover = bullet.states.create("hover");
bullethover.properties.scale = 1.3;
// Make a panning cursor
chart.cursor = new am4charts.XYCursor();
chart.cursor.behavior = "panXY";
chart.cursor.xAxis = dateAxis;
chart.cursor.snapToSeries = series;
// Create vertical scrollbar and place it before the value axis
chart.scrollbarY = new am4core.Scrollbar();
chart.scrollbarY.parent = chart.leftAxesContainer;
chart.scrollbarY.toBack();
// Create a horizontal scrollbar with previe and place it underneath the date axis
chart.scrollbarX = new am4charts.XYChartScrollbar();
chart.scrollbarX.series.push(series);
chart.scrollbarX.parent = chart.bottomAxesContainer;
chart.events.on("ready", function () {
dateAxis.zoom({start:0.79, end:1});
});
}); // end am4core.ready()
</script>
<!-- HTML -->
<div id="chartdiv"></div>
なんだか難しそうで、なにを書いているかパッとみたただけではわかりませんね。
ただ、データが記載されているところはわかるのではないでしょうか?
<script>
// Add data
chart.data = [{
"date": "2012-07-27",
"value": 13
}, {
"date": "2012-07-28",
"value": 11
}, {
"date": "2012-07-29",
"value": 15
}, {
//~省略~
"date": "2013-01-30",
"value": 81
}];
</script>
↑ここです。
この部分を体重管理アプリのモデルに合わせていきます。
###ビューファイル(本アプリ)
まずは、コントローラーから変数をもってきて算出までします。
<script>
//JSON形式で値を渡す
const weights = <%== JSON.dump(@weights) %>;
const dates = <%== JSON.dump(@dates) %>;
//表示期間を計算
var firstDate = new Date(dates[0]) //一番最初
var lastDate = new Date(dates.slice(-1)[0]) //一番最後
var termDate= (lastDate - firstDate)/ 1000 / 60 / 60 / 24 + 1 //表示する期間
</script>
細かいところはRailsにて不連続な間隔(日付など)で投稿された値をamChartsを使って折れ線グラフを作成する。を参照してください。(本記事をそのままコピペしても動きません)
さて、Demo sourceのchart.dataの値を下記のように変えてください。
<script>
// Add data
chart.data = [];
for (var j =0; j< weights.length; j++){
for (var i = 0; i < termDate; i++) {
var newDate = new Date(firstDate)
newDate.setDate(newDate.getDate() + i); //初日からi日分たす
if ((new Date(dates[j])) - (newDate)==0){
weight =weights[j]
chart.data.push({
date: newDate,
weight: weight
});
}
}
}
</script>
valueはRailsにて不連続な間隔(日付など)で投稿された値をamChartsを使って折れ線グラフを作成する。のときと同様にweightに変更してます。weightの変更箇所はその他にもあるのですべて置換してあげてください。
##初期表示(ズーム後)を直近の1週間表示にする
本記事の本題です。
まずはDemo sourceからズームっぽい記述を探してみましょう。後方から9行目付近をみてください。
<script>
chart.events.on("ready", function () {
dateAxis.zoom({start:0.79, end:1});
});
</script>
{start:0.79, end:1}の数値を試しに{start:0, end:1}かえてみてください。
変えるときは、【小ネタ】amChartsのDemo sourceをVScodeなどのエディタにコピペせず、ブラウザ上でプロパティを変更し表示を確認する方法を使うと便利です。
zoomされず、全体が表示されました。
ということは、startの数値を変更すれば直近の1週間が表示できそうです。
全体の日数はtermDateという変数で取得できてるので、
1週間は全体の日数のどれくらいの割合か出してみます。
例:termDateが70日の場合
式: 7/termDate=0.1
0.1という数値をstartに入れては駄目です。なぜならstartは0に近いほど、小さい値(日付)を取得します。
なので0.1を入れると0.1≦x≦1の範囲になり(endが1の場合)、一番古い日付から1週間後から最新の日付を範囲としてしまいます。
では、どうするかというと1から引いてあげれば良いです。
{start:1-7/termDate, end:1}としてあげます。
こうすることで0.9≦x≦1となり、直近の1週間の割合がだせます。
最後にビューファイルの全体を記載します。
<!-- Styles -->
<style>
#chartdiv {
width: 100%;
height: 500px;
}
</style>
<!-- Resources -->
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/kelly.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
<!-- Chart code -->
<script>
am4core.ready(function() {
// Themes begin
am4core.useTheme(am4themes_kelly);
am4core.useTheme(am4themes_animated);
// Themes end
// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);
const weights = <%== JSON.dump(@weights) %>;
const dates = <%== JSON.dump(@dates) %>;
var firstDate = new Date(dates[0])
var lastDate = new Date(dates.slice(-1)[0])
var termDate= (lastDate - firstDate)/ 1000 / 60 / 60 / 24 + 1
// Add data
chart.data = [];
for (var j =0; j< weights.length; j++){
for (var i = 0; i < termDate; i++) {
var newDate = new Date(firstDate)
newDate.setDate(newDate.getDate() + i); //初日からi日分たす
if ((new Date(dates[j])) - (newDate)==0){
weight =weights[j]
chart.data.push({
date: newDate,
weight: weight
});
}
}
}
// Set input format for the dates
chart.dateFormatter.inputDateFormat = "yyyy-MM-dd";
// Create axes
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
// Create series
var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.valueY = "weight";
series.dataFields.dateX = "date";
series.tooltipText = "{weight}"
series.strokeWidth = 2;
series.minBulletDistance = 15;
// Drop-shaped tooltips
series.tooltip.background.cornerRadius = 20;
series.tooltip.background.strokeOpacity = 0;
series.tooltip.pointerOrientation = "vertical";
series.tooltip.label.minWidth = 40;
series.tooltip.label.minHeight = 40;
series.tooltip.label.textAlign = "middle";
series.tooltip.label.textValign = "middle";
// Make bullets grow on hover
var bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.circle.strokeWidth = 2;
bullet.circle.radius = 4;
bullet.circle.fill = am4core.color("#fff");
var bullethover = bullet.states.create("hover");
bullethover.properties.scale = 1.3;
// Make a panning cursor
chart.cursor = new am4charts.XYCursor();
chart.cursor.behavior = "panXY";
chart.cursor.xAxis = dateAxis;
chart.cursor.snapToSeries = series;
// Create vertical scrollbar and place it before the value axis
chart.scrollbarY = new am4core.Scrollbar();
chart.scrollbarY.parent = chart.leftAxesContainer;
chart.scrollbarY.toBack();
// Create a horizontal scrollbar with previe and place it underneath the date axis
chart.scrollbarX = new am4charts.XYChartScrollbar();
chart.scrollbarX.series.push(series);
chart.scrollbarX.parent = chart.bottomAxesContainer;
chart.events.on("ready", function () {
dateAxis.zoom({start:1-7/termDate, end:1});
});
}); // end am4core.ready()
</script>
<!-- HTML -->
<div id="chartdiv"></div>