Reputation: 5865
I have two Line Charts and each has a rangeFilter
(like the one here.)
I want to synchronize the scale of the two charts. That is, when one chart changes the range view, it will change vAxis max value
to suit the maximum data in that range, and I want the other chart to change the scale to the same value.
How can I get the vAxis.viewWindow.max
in realtime?
Upvotes: 1
Views: 8529
Reputation: 19323
Here's how to do what the original question asked:
chartWrapper.draw(); // initial draw of the chart
var chart = chartWrapper.getChart();
var cli = chart.getChartLayoutInterface();
var bb = cli.getChartAreaBoundingBox();
var vAxisMax = cli.getVAxisValue(bb.top);
Reference: discussion on Google Groups: Google Visualization API.
Upvotes: 0
Reputation: 7128
If you are just asking how to determine the vAxis.viewWindow.min
(and .max
) value, you can do it with the following code:
alert('Min ViewWindow: ' + chart.getOption('vAxis.viewWindow.min') + ', Max: ' + chart.getOption('vAxis.viewWindow.max'));
(given a chart wrapper object named chart
).
You can have it tell you the max/min every time you adjust the chart by adding a statechange event to the control wrapper:
google.visualization.events.addListener(control, 'statechange', function(e) {
if(e.inProgress == false) {
alert('Min ViewWindow: ' + chart.getOption('vAxis.viewWindow.min') + ', Max: ' + chart.getOption('vAxis.viewWindow.max'));
}
This will not actually change anything, mind, it will just report what you want. If on the other hand you want your chart to change max/min viewWindow values depending on the filtered value in the chart, here is my very poor implementation of that:
function drawVisualization() {
var dashboard = new google.visualization.Dashboard(
document.getElementById('dashboard'));
var control = new google.visualization.ControlWrapper({
'controlType': 'ChartRangeFilter',
'containerId': 'control',
'options': {
// Filter by the date axis.
'filterColumnIndex': 0,
'ui': {
'chartType': 'LineChart',
'chartOptions': {
'chartArea': {'width': '90%'},
'hAxis': {'baselineColor': 'none'}
},
// Display a single series that shows the closing value of the stock.
// Thus, this view has two columns: the date (axis) and the stock value (line series).
'chartView': {
'columns': [0, 3]
},
// 1 day in milliseconds = 24 * 60 * 60 * 1000 = 86,400,000
'minRangeSize': 86400000
}
},
// Initial range: 2012-02-09 to 2012-03-20.
'state': {'range': {'start': new Date(2012, 1, 9), 'end': new Date(2012, 2, 20)}}
});
var chart = new google.visualization.ChartWrapper({
'chartType': 'CandlestickChart',
'containerId': 'chart',
'options': {
// Use the same chart area width as the control for axis alignment.
'chartArea': {'height': '80%', 'width': '90%'},
'hAxis': {'slantedText': false},
'vAxis': {'viewWindow': {'min': 0, 'max': 2000}},
'legend': {'position': 'none'}
},
// Convert the first column from 'date' to 'string'.
'view': {
'columns': [
{
'calc': function(dataTable, rowIndex) {
return dataTable.getFormattedValue(rowIndex, 0);
},
'type': 'string'
}, 1, 2, 3, 4]
}
});
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'Stock low');
data.addColumn('number', 'Stock open');
data.addColumn('number', 'Stock close');
data.addColumn('number', 'Stock high');
// Create random stock values, just like it works in reality.
var open, close = 300;
var low, high;
for (var day = 1; day < 121; ++day) {
var change = (Math.sin(day / 2.5 + Math.PI) + Math.sin(day / 3) - Math.cos(day * 0.7)) * 150;
change = change >= 0 ? change + 10 : change - 10;
open = close;
close = Math.max(50, open + change);
low = Math.min(open, close) - (Math.cos(day * 1.7) + 1) * 15;
low = Math.max(0, low);
high = Math.max(open, close) + (Math.cos(day * 1.3) + 1) * 15;
var date = new Date(2012, 0 ,day);
data.addRow([date, Math.round(low), Math.round(open), Math.round(close), Math.round(high)]);
}
// This function determines the maximum and minimum values of the data
function calculateMinMax(data) {
// Get max and min values for the data table
var totalMin = data.getValue(0,1);
var totalMax = data.getValue(0,1);
for (var i = 1;i < data.getNumberOfColumns();i++) {
for (var j = 0;j < data.getNumberOfRows();j++){
if ( data.getValue(j, i) < totalMin ) {
totalMin = data.getValue(j, i);
}
if ( data.getValue(j, i) > totalMax ) {
totalMax = data.getValue(j, i);
}
}
}
// Calculate grid line axes and min/max settings
// Figure out the largest number (positive or negative)
var biggestNumber = Math.max(Math.abs(totalMax),Math.abs(totalMin));
// Round to an exponent of 10 appropriate for the biggest number
var roundingExp = Math.floor(Math.log(biggestNumber) / Math.LN10);
var roundingDec = Math.pow(10,roundingExp);
// Round your max and min to the nearest exponent of 10
var newMax = Math.ceil(totalMax/roundingDec)*roundingDec;
var newMin = Math.floor(totalMin/roundingDec)*roundingDec;
// Determine the range of your values
var range = newMax - newMin;
// Define the number of gridlines (default 5)
var gridlines = 5;
// Determine an appropriate gap between gridlines
var interval = range / (gridlines - 1);
// Round that interval up to the exponent of 10
var newInterval = Math.ceil(interval/roundingDec)*roundingDec;
// Re-round your max and min to the new interval
var finalMax = Math.ceil(totalMax/newInterval)*newInterval;
var finalMin = Math.floor(totalMin/newInterval)*newInterval;
var result = [finalMin, finalMax];
return result;
}
var axisMinMax = calculateMinMax(data);
alert('Min: ' + axisMinMax[0] + ', Max: ' + axisMinMax[1]);
chart.setOption('vAxis.viewWindow.min', axisMinMax[0]);
chart.setOption('vAxis.viewWindow.max', axisMinMax[1]);
dashboard.bind(control, chart);
dashboard.draw(data);
google.visualization.events.addListener(control, 'statechange', function(e) {
if(e.inProgress == false) {
var axisMinMax = calculateMinMax(chart.getDataTable());
chart.setOption('vAxis.viewWindow.min', axisMinMax[0]);
chart.setOption('vAxis.viewWindow.max', axisMinMax[1]);
var filteredData = chart.getDataTable();
chart.draw(filteredData);
}
});
}
Upvotes: 4
Reputation: 26340
Without knowing more specifics about your charts, I can't give you a very detailed answer, but assuming you have two charts (chart1
and chart2
) driven by two controls (control1
and control2
, respectively) in a Dashboard, and each chart has one data series each, then you could use something like this to sync the scales:
function syncChartScales () {
var range1 = chart1.getDataTable().getColumnRange(1);
var range2 = chart2.getDataTable().getColumnRange(1);
var minMax = {
min: Math.min(range1.min, range2.min),
max: Math.max(range1.max, range2.max)
}
chart1.setOption('vAxis.minValue', minMax.min);
chart1.setOption('vAxis.maxValue', minMax.max);
chart2.setOption('vAxis.minValue', minMax.min);
chart2.setOption('vAxis.maxValue', minMax.max);
chart1.draw();
chart2.draw();
}
google.visualization.events.addListener(control1, 'statechange', syncChartScales);
google.visualization.events.addListener(control2, 'statechange', syncChartScales);
If you have more data series, then it becomes slightly more complicated, as you must get the range of all data series in both charts to find the min/max of them all, and set the vAxis.minValue/maxValue
options of both charts to the min/max of all series.
Upvotes: 2