amChartsを使わせもらいました。
このamChartsですが、jsのlibになってるんですが
かなりの高機能なチャートを簡単に実装できます。
rails で実装したので、多少日本向けに変更したソースを参考までに公開します。
Gemfile
gem "amcharts-rails"
application.js
//= require amcharts
views/xxxxx/xxxx.html.erb
...... <%= render :partial => "candlestick_nikkei_avg" %> ......
views/xxxxx/_candlestick_nikkei_avg.html.erb
<div id="chartdiv" style="width:100%; height:400px;"></div>
<div style="float:right;margin-right:20px;">
<input onChange="changeZoomDates()" style="width:100px; text-align:center" type="text" id="startDate">-
<input onChange="changeZoomDates()" style="width:100px; text-align:center" type="text" id="endDate">
</div>
<script type="text/javascript">
var chart;
var graph;
var graphType = "candlestick";
var maxCandlesticks = 100;
var dataString = "<%= @nikkei_avg_str -%>";
var chartData = [];
AmCharts.ready(function () {
// first parse data string
parseData();
// SERIAL CHART
chart = new AmCharts.AmSerialChart();
chart.pathToImages = "/assets/amcharts/";
chart.dataProvider = chartData;
chart.categoryField = "date";
// listen for dataUpdated event ad call "zoom" method then it happens
chart.addListener('dataUpdated', zoomChart);
// listen for zoomed event andcall "handleZoom" method then it happens
chart.addListener('zoomed', handleZoom);
// AXES
// category
var categoryAxis = chart.categoryAxis;
categoryAxis.parseDates = true; // as our data is date-based, we set this to true
categoryAxis.minPeriod = "DD"; // our data is daily, so we set minPeriod to "DD"
categoryAxis.dashLength = 1;
categoryAxis.tickLenght = 0;
categoryAxis.inside = true;
// value
var valueAxis = new AmCharts.ValueAxis();
valueAxis.dashLength = 1;
valueAxis.axisAlpha = 0;
chart.addValueAxis(valueAxis);
// GRAPH
graph = new AmCharts.AmGraph();
graph.title = "Price:";
// as candlestick graph looks bad when there are a lot of candlesticks, we set initial type to "line"
graph.type = "line";
// graph colors
graph.lineColor = "#7f8da9";
graph.fillColors = "#7f8da9";
graph.negativeLineColor = "#db4c3c";
graph.negativeFillColors = "#db4c3c";
graph.fillAlphas = 1;
// candlestick graph has 4 fields - open, low, high, close
graph.openField = "open";
graph.highField = "high";
graph.lowField = "low";
graph.closeField = "close";
// this one is for "line" graph type
graph.valueField = "close";
chart.addGraph(graph);
// CURSOR
var chartCursor = new AmCharts.ChartCursor();
chart.addChartCursor(chartCursor);
// SCROLLBAR
var chartScrollbar = new AmCharts.ChartScrollbar();
chartScrollbar.scrollbarHeight = 30;
chartScrollbar.graph = graph; // as we want graph to be displayed in the scrollbar, we set graph here
chartScrollbar.graphType = "line"; // we don't want candlesticks to be displayed in the scrollbar
chartScrollbar.gridCount = 4;
chartScrollbar.color = "#FFFFFF";
chart.addChartScrollbar(chartScrollbar);
// WRITE
chart.write("chartdiv");
});
// this method is called when chart is first inited as we listen for "dataUpdated" event
function zoomChart() {
// different zoom methods can be used - zoomToIndexes, zoomToDates, zoomToCategoryValues
chart.zoomToIndexes(chartData.length - 30, chartData.length - 1);
}
// this methid is called each time the selected period of the chart is changed
function handleZoom(event) {
var startDate = event.startDate;
var endDate = event.endDate;
// document.getElementById("startDate").value = AmCharts.formatDate(startDate, "DD/MM/YYYY");
// document.getElementById("endDate").value = AmCharts.formatDate(endDate, "DD/MM/YYYY");
document.getElementById("startDate").value = AmCharts.formatDate(startDate, "YYYY/MM/DD");
document.getElementById("endDate").value = AmCharts.formatDate(endDate, "YYYY/MM/DD");
// as we also want to change graph type depending on the selected period, we call this method
changeGraphType(event);
}
// changes graph type to line/candlestick, depending on the selected range
function changeGraphType(event) {
var startIndex = event.startIndex;
var endIndex = event.endIndex;
if (endIndex - startIndex > maxCandlesticks) {
// change graph type
if (graph.type != "line") {
graph.type = "line";
graph.fillAlphas = 0;
chart.validateNow();
}
} else {
// change graph type
if (graph.type != graphType) {
graph.type = graphType;
graph.fillAlphas = 1;
chart.validateNow();
}
}
}
// Parse data
function parseData() {
// split data string into array
var rowArray = dataString.split("\n");
// loop through this array and create data items
for (var i = rowArray.length - 1; i > -1; i--) {
var row = rowArray[i].split(",");
var dateArray = row[0].split("-");
// we have to subtract 1 from month, as months in javascript are zero-based
var date = new Date(Number(dateArray[0]), Number(dateArray[1]) - 1, Number(dateArray[2]));
var open = row[1];
var high = row[2];
var low = row[3];
var close = row[4];
chartData.push({
date: date,
open: open,
high: high,
low: low,
close: close
});
}
}
// this method converts string from input fields to date object
function stringToDate(str) {
var dArr = str.split("/");
var date = new Date(Number(dArr[2]), Number(dArr[1]) - 1, dArr[0]);
return date;
}
// this method is called when user changes dates in the input field
function changeZoomDates() {
var startDateString = document.getElementById("startDate").value;
var endDateString = document.getElementById("endDate").value;
var startDate = stringToDate(startDateString);
var endDate = stringToDate(endDateString);
chart.zoomToDates(startDate, endDate);
}
</script>
controllers/xxxxxx.rb
・・・・ @nikkei_avg_str = nikkei_avg_str ・・・・ def self.nikkei_avg_str nikkei_averages = DailyStockPrice.where('code = ? and hiduke >= ? and hiduke <= ?', NIKKEI_AVERAGE_CODE, Date.today - 1.year, Date.today).order('hiduke desc') candle_chart_str(nikkei_averages) end private def self.candle_chart_str(daily_stock_prices) str = '' # '日付,始値,高値,安値,終値\n' # 行末に\nがあるとちゃんと表示されない。 daily_stock_prices.each_with_index do |daily_stock_price, i| str = str + '\n' if i > 0 str = str + daily_stock_price.hiduke.strftime('%Y-%m-%d') + ',' str = str + daily_stock_price.hajimarine.to_s + ',' str = str + daily_stock_price.takane.to_s + ',' str = str + daily_stock_price.yasune.to_s + ',' str = str + daily_stock_price.owarine.to_s end str end
注意
amChartsのサイトからamCharts.jsをダウンロードして、jsをインクルードしたら
production環境でエラーになりました。
gemでインストールすることで解消しました。
amChartsはかなりの優れもので
他にも、下記のようなものもあったりして
http://www.amcharts.com/stock-chart/multiple-panels/
株価と出来高も一緒に表示できちゃいそうですね。
ありがとうございます。
amChartsさん