Chart.jsを使用してそれが可能かどうかお聞きしたいですhttp://www.chartjs.org/棒グラフと折れ線グラフを組み合わせたグラフを取得するには?
アドバイスをいただければ幸いです。
ベストアンサー1
以下の回答はchart.js 1.xに関するものです。Chart.js 2.xはこれをサポートしています。Chart.js で棒グラフと折れ線グラフを組み合わせたグラフを取得するにはどうすればよいでしょうか?
編集2この機能をchartjsのカスタムビルドに追加しました。https://github.com/leighquince/Chart.js唯一の違いは、これを LineBar ではなく Overlay と名付けたことです。これを使用するには、グラフを作成するだけで済みます。var myOverlayChart = new Chart(lineBar).Overlay(data);
他のすべては同じです。
さて、これが可能かどうかを簡単に調べてみたところ、簡単に答えると「はい」ですが、これをチャート js のビルドに完全に統合するにはさらに作業が必要です。以下は、比較のために折れ線グラフと棒グラフで動作を示すフィドルです。http://fiddle.jshell.net/leighking2/898kzyp7/
そこで、私の解決策は、LineBar という新しいチャート タイプを作成することでした (拡張オプションを選択することもできましたが、開始する前に、これには多くのメソッドのオーバーライドが必要になると感じたため、新しいグラフを選択しました。これにより、ヘルパーを Chart.helpers として再宣言する必要もなくなりました。これは大したことではありませんが、当時は十分な理由でした)。
本質的には棒グラフですが、データセットを別々に変数で追跡しlineDataSets
ますbarDataSets
。その後、描画/イベントのチェック/データの使用が必要になると、他の 2 つの新しいデータセットを個別にループします。
変数をループするときは常に、lineDataSets
現在の折れ線グラフのコードが実行され、棒グラフの場合はその逆になります。
新しいグラフはかなり大きいので、この回答の下部に貼り付けます。これを使用するには、下部にある独自の chart.js ファイルにコピーして貼り付けるか、ページに chart.js を含めた後に貼り付けます。
それを利用するには、追加オプションを使用してデータを宣言します。type
var data = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
label: "My First dataset",
//new option, type will default to bar as that what is used to create the scale
type: "line",
fillColor: "rgba(220,220,220,0.2)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: [65, 59, 4, 81, 56, 55, 40]
}, {
label: "My First dataset",
//new option, type will default to bar as that what is used to create the scale
type: "bar",
fillColor: "rgba(220,20,220,0.2)",
strokeColor: "rgba(220,20,220,1)",
pointColor: "rgba(220,20,220,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: [32, 25, 33, 88, 12, 92, 33]
}]
};
次に、LineBarタイプの新しいチャートを作成します。
var lineBar = document.getElementById("line-bar").getContext("2d");
var myLineBarChart = new Chart(lineBar).LineBar(data);
結果
編集:更新されたので、ツールチップと removeData/addData 機能が動作するようになりました。これらの例については、フィドルを参照してください。また、折れ線グラフと棒グラフの両方で、データセットを好きなだけ追加でき、それらはすべて同じグラフに表示されます。
制限 - バーと線が更新されると、それぞれの部分もここで更新される必要があり、これはあまり良くありません。バーと線が更新されても壊れることはありません。ただ、何が更新されても同じに見えない可能性があります。
そしてこれが実際の新しいチャートです
//new chart type LineBar - its a bit like bar and line
//were slammed together at high speed, not pretty,
//but they are part of each other now
(function(){
"use strict";
var root = this,
Chart = root.Chart,
helpers = Chart.helpers;
var defaultConfig = {
//Function - Whether the current x-axis label should be filtered out, takes in current label and
//index, return true to filter out the label return false to keep the label
labelsFilter : function(label,index){return false;},
//Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
scaleBeginAtZero : true,
//Boolean - Whether grid lines are shown across the chart
scaleShowGridLines : true,
//String - Colour of the grid lines
scaleGridLineColor : "rgba(0,0,0,.05)",
//Number - Width of the grid lines
scaleGridLineWidth : 1,
//Boolean - If there is a stroke on each bar
barShowStroke : true,
//Number - Pixel width of the bar stroke
barStrokeWidth : 2,
//Number - Spacing between each of the X value sets
barValueSpacing : 5,
//Number - Spacing between data sets within X values
barDatasetSpacing : 1,
//Boolean - Whether the line is curved between points
bezierCurve : true,
//Number - Tension of the bezier curve between points
bezierCurveTension : 0.4,
//Boolean - Whether to show a dot for each point
pointDot : true,
//Number - Radius of each point dot in pixels
pointDotRadius : 4,
//Number - Pixel width of point dot stroke
pointDotStrokeWidth : 1,
//Number - amount extra to add to the radius to cater for hit detection outside the drawn point
pointHitDetectionRadius : 20,
//Boolean - Whether to show a stroke for datasets
datasetStroke : true,
//Number - Pixel width of dataset stroke
datasetStrokeWidth : 2,
//Boolean - Whether to fill the dataset with a colour
datasetFill : true,
//String - A legend template
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].fillColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
};
Chart.Type.extend({
name: "LineBar",
defaults : defaultConfig,
initialize: function(data){
//Expose options as a scope variable here so we can access it in the ScaleClass
var options = this.options;
//two new varibale to hold the different graph types
this.barDatasets = [];
this.lineDatasets = [];
//generate the scale, let bar take control here as he needs the width.
this.ScaleClass = Chart.Scale.extend({
offsetGridLines : true,
calculateBarX : function(datasetCount, datasetIndex, barIndex){
//Reusable method for calculating the xPosition of a given bar based on datasetIndex & width of the bar
var xWidth = this.calculateBaseWidth(),
xAbsolute = this.calculateX(barIndex) - (xWidth/2),
barWidth = this.calculateBarWidth(datasetCount);
return xAbsolute + (barWidth * datasetIndex) + (datasetIndex * options.barDatasetSpacing) + barWidth/2;
},
calculateBaseWidth : function(){
return (this.calculateX(1) - this.calculateX(0)) - (2*options.barValueSpacing);
},
calculateBarWidth : function(datasetCount){
//The padding between datasets is to the right of each bar, providing that there are more than 1 dataset
var baseWidth = this.calculateBaseWidth() - ((datasetCount - 1) * options.barDatasetSpacing);
return (baseWidth / datasetCount);
}
});
//Declare the extension of the default point, to cater for the options passed in to the constructor
this.PointClass = Chart.Point.extend({
strokeWidth : this.options.pointDotStrokeWidth,
radius : this.options.pointDotRadius,
display: this.options.pointDot,
hitDetectionRadius : this.options.pointHitDetectionRadius,
ctx : this.chart.ctx,
inRange : function(mouseX){
return (Math.pow(mouseX-this.x, 2) < Math.pow(this.radius + this.hitDetectionRadius,2));
}
});
this.datasets = [];
//Set up tooltip events on the chart
if (this.options.showTooltips){
helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
var activeData = (evt.type !== 'mouseout') ? this.getDataAtEvent(evt) : [];
this.eachBars(function(bar){
bar.restore(['fillColor', 'strokeColor']);
});
this.eachPoints(function(point){
point.restore(['fillColor', 'strokeColor']);
});
helpers.each(activeData, function(active){
active.fillColor = active.highlightFill;
active.strokeColor = active.highlightStroke;
});
this.showTooltip(activeData);
});
}
//Declare the extension of the default point, to cater for the options passed in to the constructor
this.BarClass = Chart.Rectangle.extend({
strokeWidth : this.options.barStrokeWidth,
showStroke : this.options.barShowStroke,
ctx : this.chart.ctx
});
//Iterate through each of the datasets, and build this into a property of the chart
helpers.each(data.datasets,function(dataset,datasetIndex){
var datasetObject = {
label : dataset.label || null,
fillColor : dataset.fillColor,
strokeColor : dataset.strokeColor,
type: dataset.type,
bars : [],
pointColor : dataset.pointColor,
pointStrokeColor : dataset.pointStrokeColor,
points : []
};
this.datasets.push(datasetObject);
switch(dataset.type)
{
case "line":
this.lineDatasets.push(datasetObject);
helpers.each(dataset.data,function(dataPoint,index){
//Add a new point for each piece of data, passing any required data to draw.
datasetObject.points.push(new this.PointClass({
value : dataPoint,
label : data.labels[index],
datasetLabel: dataset.label,
strokeColor : dataset.pointStrokeColor,
fillColor : dataset.pointColor,
highlightFill : dataset.pointHighlightFill || dataset.pointColor,
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
}));
},this);
break;
default:
this.barDatasets.push(datasetObject);
helpers.each(dataset.data,function(dataPoint,index){
//Add a new point for each piece of data, passing any required data to draw.
datasetObject.bars.push(new this.BarClass({
value : dataPoint,
label : data.labels[index],
datasetLabel: dataset.label,
strokeColor : dataset.strokeColor,
fillColor : dataset.fillColor,
highlightFill : dataset.highlightFill || dataset.fillColor,
highlightStroke : dataset.highlightStroke || dataset.strokeColor
}));
},this);
break;
}
},this);
this.buildScale(data.labels);
helpers.each(this.lineDatasets,function(dataset,datasetIndex){
//Iterate through each of the datasets, and build this into a property of the chart
this.eachPoints(function(point, index){
helpers.extend(point, {
x: this.scale.calculateX(index),
y: this.scale.endPoint
});
point.save();
}, this);
},this);
this.BarClass.prototype.base = this.scale.endPoint;
this.eachBars(function(bar, index, datasetIndex){
helpers.extend(bar, {
width : this.scale.calculateBarWidth(this.barDatasets.length),
x: this.scale.calculateBarX(this.barDatasets.length, datasetIndex, index),
y: this.scale.endPoint
});
bar.save();
}, this);
this.render();
},
update : function(){
this.scale.update();
// Reset any highlight colours before updating.
helpers.each(this.activeElements, function(activeElement){
activeElement.restore(['fillColor', 'strokeColor']);
});
this.eachBars(function(bar){
bar.save();
});
this.eachPoints(function(point){
point.save();
});
this.render();
},
eachPoints : function(callback){
//use the lineDataSets
helpers.each(this.lineDatasets,function(dataset){
helpers.each(dataset.points,callback,this);
},this);
},
eachBars : function(callback){
//user the barDataSets
helpers.each(this.barDatasets,function(dataset, datasetIndex){