I found the code from here:
On load Google LineChart animation
google.load('visualization', '1', { packages: ['corechart'], callback: function() {
var data = new google.visualization.DataTable();
data.addRows(5);
data.addColumn('string', '');
data.addColumn('number', 'Sales');
data.addRows(5);
data.setValue(0, 0, 'Jan');
data.setValue(1, 0, 'Feb');
data.setValue(2, 0, 'Mar');
data.setValue(3, 0, 'Apr');
data.setValue(4, 0, 'May');
var options = {
title: 'Sales by months for 2013 year', curveType: 'function',
"vAxis": { "minValue": "0", "maxValue": 6 }, "hAxis": { "slantedTextAngle": "45", "slantedText": "true" }, "legend": { "position": "top" }, "pointSize": "5",
animation: { duration: 250 }
};
var chart = new google.visualization.LineChart(document.getElementById('test'));
var index = 0;
var chartData = [ 5, 1, 4, 2, 3 ]
var drawChart = function() {
console.log('drawChart index ' + index);
if (index < chartData.length) {
data.setValue(index, 1, chartData[index++]);
chart.draw(data, options);
}
}
google.visualization.events.addListener(chart, 'animationfinish', drawChart);
chart.draw(data, options);
drawChart();
}});
If I want to create multi-line, how to modify this code? Thanks!
I'm not a javascript programmer and not familiar with OOP
The author is OneMoreVladimir, but I don't have the access to comment under his post.
google.load('visualization', '1', {
packages: ['corechart'],
callback: function() {
var data = new google.visualization.DataTable();
data.addRows(5);
data.addColumn('string', '');
data.addColumn('number', 'Sales');
data.addColumn('number', 'Sales2');
data.addRows(5);
data.setValue(0, 0, 'Jan');
data.setValue(1, 0, 'Feb');
data.setValue(2, 0, 'Mar');
data.setValue(3, 0, 'Apr');
data.setValue(4, 0, 'May');
var options = {
title: 'Sales by months for 2013 year',
curveType: 'function',
"vAxis": {
"minValue": "0",
"maxValue": 8
},
"hAxis": {
"slantedTextAngle": "45",
"slantedText": "true"
},
"legend": {
"position": "top"
},
"pointSize": "5",
animation: {
duration: 600
}
};
var chart = new google.visualization.LineChart(document.getElementById('test'));
var index = 0;
var chartData = [5, 1, 4, 2, 3]
var drawChart = function() {
console.log('drawChart index ' + index);
if (index < chartData.length) {
data.setValue(index, 1, chartData[index++]);
chart.draw(data, options);
}
}
var index1 = 0;
var chartData1 = [1, 3, 4, 6, 5]
var drawChart1 = function() {
console.log('drawChart1 index1 ' + index1);
if (index1 < chartData1.length) {
data.setValue(index1, 2, chartData1[index1++]);
chart.draw(data, options);
}
}
google.visualization.events.addListener(chart, 'animationfinish', drawChart);
google.visualization.events.addListener(chart, 'animationfinish', drawChart1);
chart.draw(data, options);
drawChart();
drawChart1();
}
});
I figure out! Here is the code.
But another question, the code pass the http://jsfiddle.net and run very well, but when I copy paste it into the HTML why it doesn't work? Did I miss something?
Related
How to detect click on an axis label with chart.js
In the example bellow, I can only detect click on the graph itself
https://stackblitz.com/edit/ng2-charts-bar-template-qchyz6
You will need to implement a custom plugin that can listen to all the events of the canvas:
const findLabel = (labels, evt) => {
let found = false;
let res = null;
labels.forEach(l => {
l.labels.forEach((label, index) => {
if (evt.x > label.x && evt.x < label.x2 && evt.y > label.y && evt.y < label.y2) {
res = {
label: label.label,
index
};
found = true;
}
});
});
return [found, res];
};
const getLabelHitboxes = (scales) => (Object.values(scales).map((s) => ({
scaleId: s.id,
labels: s._labelItems.map((e, i) => ({
x: e.translation[0] - s._labelSizes.widths[i],
x2: e.translation[0] + s._labelSizes.widths[i] / 2,
y: e.translation[1] - s._labelSizes.heights[i] / 2,
y2: e.translation[1] + s._labelSizes.heights[i] / 2,
label: e.label,
index: i
}))
})));
const plugin = {
id: 'customHover',
afterEvent: (chart, event, opts) => {
const evt = event.event;
if (evt.type !== 'click') {
return;
}
const [found, labelInfo] = findLabel(getLabelHitboxes(chart.scales), evt);
if (found) {
console.log(labelInfo);
}
}
}
Chart.register(plugin);
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'orange'
}
]
},
options: {}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
</body>
Adpatation for Angular with ng2-charts (chart-js v3.7.1)
Just use Chart.register
i.e. put the following functiion into component ngOnInit()
RegisterPlugin() {
Chart.register(
{
id: 'yAxisCustomClick',
afterEvent: (chart: Chart<'bar'>, event: {
event: ChartEvent;
replay: boolean;
changed?: boolean | undefined;
cancelable: false;
inChartArea: boolean
}) => {
const evt = event.event;
if (evt.type === 'click' && evt.x! < Object.values(chart.scales).filter(s => s.id === 'x')[0].getBasePixel()) {
const labelIndex = Object.values(chart.scales).filter(s => s.id === 'y')[0].getValueForPixel(evt.y!);
const label = Object.values(chart.scales).filter(s => s.id === 'y')[0].getTicks()[labelIndex!]?.label;
if (label) {
console.log('Do the stuff for', label)
}
}
}
}
);
}
Example in stackblitz udpated
https://stackblitz.com/edit/ng2-charts-bar-template-qchyz6
I am working with chartjs, I am trying to animate chart from right to left or left to right on load.
var canvas = document.getElementById('chart_canvas');
var ctx = canvas.getContext('2d');
// Generate random data to plot
var DATA_POINT_NUM = 10;
var data = {
labels: [],
datasets: [
{
data: [],
},
]
}
for (var i=0; i<DATA_POINT_NUM; i++) {
data.datasets[0].data.push(Math.random()*10);
data.labels.push(String.fromCharCode(65+i));
}
var oldDraw = Chart.controllers.line.prototype.draw;
Chart.controllers.line.prototype.draw = function(animationFraction) {
var animationConfig = this.chart.options.animation;
if (animationConfig.xAxis === true) {
var ctx = this.chart.chart.ctx;
var hShift = (1-animationFraction)*ctx.canvas.width;
ctx.save();
ctx.setTransform(1, 0, 0, 1, hShift,0);
if (animationConfig.yAxis === true) {
oldDraw.call(this, animationFraction);
} else {
oldDraw.call(this, 1);
}
ctx.restore();
} else if (animationConfig.yAxis === true) {
oldDraw.call(this, animationFraction);
} else {
oldDraw.call(this, 1);
}
}
var lineChart = new Chart(ctx, {
type: 'line',
data: data,
options: {
animation: {
duration: 5000,
xAxis: true,
yAxis: true,
}
}
});
Example 1
The above code works fine on windows, but I'm facing issue on mac devices.While animating from left to right the data displays incorrectly means that the data moves to upward from x axis.How to fix this issue?
I am attaching screenshot.
Screenshot
Please change setTransform to transform.
Try the following code
var canvas = document.getElementById('chart_canvas');
var ctx = canvas.getContext('2d');
// Generate random data to plot
var DATA_POINT_NUM = 10;
var data = {
labels: [],
datasets: [
{
data: [],
},
]
}
for (var i=0; i<DATA_POINT_NUM; i++) {
data.datasets[0].data.push(Math.random()*10);
data.labels.push(String.fromCharCode(65+i));
}
var oldDraw = Chart.controllers.line.prototype.draw;
Chart.controllers.line.prototype.draw = function(animationFraction) {
var animationConfig = this.chart.options.animation;
if (animationConfig.xAxis === true) {
var ctx = this.chart.chart.ctx;
var hShift = (1-animationFraction)*ctx.canvas.width;
ctx.save();
ctx.transform(1, 0, 0, 1, hShift,0);
if (animationConfig.yAxis === true) {
oldDraw.call(this, animationFraction);
} else {
oldDraw.call(this, 1);
}
ctx.restore();
} else if (animationConfig.yAxis === true) {
oldDraw.call(this, animationFraction);
} else {
oldDraw.call(this, 1);
}
}
var lineChart = new Chart(ctx, {
type: 'line',
data: data,
options: {
animation: {
duration: 5000,
xAxis: true,
yAxis: true,
}
}
});
Here is the jfiddle - http://jsfiddle.net/inasisi/6v639g9g/1/
As you can see the X axis is not scaled properly. I can calculate the min and max date and set the scale properly but don't want to do it after each filter. Would prefer if elasticX works properly.
Any ideas?
var chartGroup = "chartGroup";
data = [{
"run_date": "2013-01-20",
"current_grade": "Kindergarten",
"students": 1
}, {
"run_date": "2013-01-20",
"current_grade": "First",
"students": 2
}, {
"run_date": "2014-03-22",
"current_grade": "Kindergarten",
"students": 3
}, {
"run_date": "2014-03-22",
"current_grade": "First",
"students": 4
}, {
"run_date": "2015-10-06",
"current_grade": "Kindergarten",
"students": 5
}, {
"run_date": "2015-10-06",
"current_grade": "First",
"students": 21
}, {
"run_date": "2015-02-13",
"current_grade": "Kindergarten",
"students": 31
}, {
"run_date": "2015-02-13",
"current_grade": "First",
"students": 26
}, ];
var ndx = crossfilter(data);
var dateFormat = d3.time.format("%Y-%m-%d");
data.forEach(function (d) {
d.run_date = Date.parse(d.run_date);
});
var ndx = crossfilter(data);
filterDateDimension = ndx.dimension(function (d) {
return [d.run_date];
});
dateDimension = ndx.dimension(function (d) {
return [d.run_date];
});
var minDate = dateDimension.bottom(1)[0].run_date;
var maxDate = dateDimension.top(1)[0].run_date;
var runsStudentsGroup = dateDimension.group().reduceSum(function (fact) {
return fact.students;
});
var totalStudentsChart = dc.lineChart("#students_chart", chartGroup);
totalStudentsChart.renderArea(true)
.width(300)
.height(300)
.x(d3.time.scale())
.elasticY(true)
.elasticX(true)
.renderHorizontalGridLines(true)
.renderVerticalGridLines(true)
.dimension(dateDimension)
//.colors('red')
.group(runsStudentsGroup);
dc.renderAll(chartGroup);
$('.day_filter').on('click', function () {
console.log(dateDimension.top(Infinity));
console.log($(this).val());
dateDimension.filter(function (d) {
console.log(d > new Date(2015, 0, 1));
return d > new Date(2015, 0, 1);
});
console.log(dateDimension.top(Infinity));
dc.redrawAll();
});
I had to fix a few things to get the chart to display and to get the filter to work at all. I'll just quote those without explaining, since those aren't what the question is about:
d.run_date = new Date(d.run_date);
//...
return d.run_date; // twice
//...
filterDateDimension.filter(function (d) {
//...
dc.redrawAll(chartGroup);
To answer your main question, which is frequently asked, crossfilter does not automatically remove empty bins. You can use a "fake group" to filter them out.
Adding:
function remove_empty_bins(source_group) {
return {
all:function () {
return source_group.all().filter(function(d) {
return d.value != 0;
});
}
};
}
//...
.group(remove_empty_bins(runsStudentsGroup));
Working fork of your fiddle here: http://jsfiddle.net/gordonwoodhull/8an2n1eL/5/
(The transition in this example is particularly screwy, and will be fixed in 2.1.)
I have a jqplot line graph with this line:
`var line = [[1,0.493],
[1,1.286],
[2,0.305],
[2,0.516],
[2,0.551],
[2,0.595],
[2,0.609],
[2,0.644],
[2,0.65],
[2,1.249],
[2,1.265],
[4,0.443],
[5,0.288],
[5,0.477],
[5,0.559],
[5,0.562],
[6,0.543],
[7,0.513],
[7,0.549],
[8,0.442],
[8,0.467],
[8,0.468],
[8,0.597],
[8,0.857]];`
Im using tooltipContentEditor to display the x and y values of the point on hover. I need the values displayed to be exact.
Here is the code Im using: http://jsfiddle.net/ZQh38/1/
The problem:
Sometimes, the x and y values displayed are incorrect. For example, the last points at (6, 0.5) and (7, 0.5)
The values are only displayed with 1 decimal, which needs to be 3.
So, the question is, how do I get the exact y values?
Ive also tried to use the pointIndex, which does NOT match with the values in the line.
Thanks for your help!
Here is the solution to your problem: jsFiddle example
I made changes to your highlighter option.
/*
Drawing graphs
*/
var Statistics = {
scatter: false,
trendline: false,
enableLabels: true,
showAverage: false,
colour: null,
//Graph properties
scatterPlot: function(on){
Statistics.scatter = on;
},
showTrendline: function(on){
$.jqplot.config.enablePlugins = on;
Statistics.trendline = on;
},
disableLabels: function(yes){
Statistics.enableLabels = (!yes);
},
shouldDrawScatter: function(){
return (!Statistics.scatter);
},
useLabels: function(){
return Statistics.enableLabels;
},
getTrendline: function(){
return Statistics.trendline;
},
//Drawing
drawLabels: function(){
document.getElementById('ylabel').innerHTML = Statistics.ylabel;
document.getElementById('xlabel').innerHTML = Statistics.xlabel;
},
generateGraph: function(){
var line = [[1,0.493],
[1,1.286],
[2,0.305],
[2,0.516],
[2,0.551],
[2,0.595],
[2,0.609],
[2,0.644],
[2,0.65],
[2,1.249],
[2,1.265],
[4,0.443],
[5,0.288],
[5,0.477],
[5,0.559],
[5,0.562],
[6,0.543],
[7,0.513],
[7,0.549],
[8,0.442],
[8,0.467],
[8,0.468],
[8,0.597],
[8,0.857]];
var plot = $.jqplot('chart', [line], {
animate: true,
grid:{backgroundColor: 'white'},
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: [1, 2, 3, 4, 5, 6, 7],
tickOptions: {
fontFamily: '"Helvetica", cursive',
fontSize: '12pt'
}
},
yaxis: {
tickOptions: {
fontFamily: '"Helvetica", cursive',
fontSize: '12pt'
},
max: 2,
min: 0
}
},
series:[{
color: "#594A42",
lineWidth: 2.5,
shadow: false,
fillColor: "#594A42",
markerOptions: {
style:'filledCircle',
color: "#594A42",
shadow: false,
size: 10
},
showLine: false,
trendline: {
color: '#999'
},
rendererOptions:{
animation: {
speed: 2000 //Speeding up animation
}
}
}],
highlighter: {
show: true,
fadeTooltip: true,
sizeAdjust: 6,
tooltipContentEditor: function(str, pointIndex, index, plot){
var splitted = plot._plotData[1][index];
var x = splitted[0];
var y = splitted[1];
return x + ", " + y;
}
}
});
},
//Checks if the graph will be a straight line
straightLine: function(lineArray){
if(typeof lineArray != 'undefined' && lineArray.length > 0) {
for(var i = 1; i < lineArray.length; i++)
{
if(lineArray[i] !== lineArray[0])
return false;
}
}
return true;
},
};
Statistics.generateGraph();
I have the following code (see below). The question is how to hide the formatter textbox for column quantity_value1 whenever the value of the column condition1 is 0.
var response = {
"id": 1,
"items": [
{"condition1": 1, "quantity_value1":"value1"},
{"condition1": 1, "quantity_value1":"value2"},
{"condition1": 0, "quantity_value1":"value3"},
{"condition1": 1, "quantity_value1":"value4"},
{"condition1": 0, "quantity_value1":"value5"}
]
};
var bpColumns = [
{label:'header1', children:[
{
key:"condition1"
},
{
key:"quantity_value1",
formatter:YAHOO.widget.DataTable.formatTextbox
}]}
];
YAHOO.example.Data = response;
this.bpDataSource = new YAHOO.util.DataSource(YAHOO.example.Data);
this.bpDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
this.bpDataSource.responseSchema = {
resultsList: "items",
fields: ["condition1","quantity_value1"]
};
this.standardSelectDataTable = new YAHOO.widget.ScrollingDataTable("mydiv",
bpColumns, this.bpDataSource, {height:"15em"});
You will have to write your own formatter as shown here in the user guide. There is an example here. There is no way to configure the built-in one, but you might use it as a the basis for your version, search for formatTextbox in the source.
This works:
var response = {
"id": 1,
"items": [
{"condition1": 1, "quantity_value1":"value1"},
{"condition1": 1, "quantity_value1":"value2"},
{"condition1": 0, "quantity_value1":"value3"},
{"condition1": 1, "quantity_value1":"value4"},
{"condition1": 0, "quantity_value1":"value5"}
]
};
var bpColumns = [
{label:'header1', children:[
{
key:"condition1"
},
{
key:"quantity_value1",
formatter:"formatTextbox"
}]}
];
var vrecord = null;
YAHOO.example.Data = response;
this.formatTextbox = function(el, oRecord, oColumn, oData, oDataTable) {
if (oRecord.getData("condition1") === 1){
var value = (YAHOO.lang.isValue(oData)) ? YAHOO.lang.escapeHTML(oData.toString()) : "";
var input = document.createElement("input");
input.type = "text";
input.value = value;
input.onchange = function()
{
vrecord.setData("quantity_value1",this.value);
console.log(vrecord);
};
el.appendChild(input);
}
};
// Add the custom formatter to the shortcuts
YAHOO.widget.DataTable.Formatter.formatTextbox = this.formatTextbox;
this.bpDataSource = new YAHOO.util.DataSource(YAHOO.example.Data);
this.bpDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
this.bpDataSource.responseSchema = {
resultsList: "items",
fields: ["condition1","quantity_value1"]
};
this.standardSelectDataTable = new YAHOO.widget.ScrollingDataTable("mydiv",
bpColumns, this.bpDataSource, {height:"15em"});
this.standardSelectDataTable.subscribe("rowClickEvent", this.standardSelectDataTable.onEventSelectRow);
this.standardSelectDataTable.subscribe("rowClickEvent", function(event, target) {
var selectedRows = this.getSelectedRows();
vrecord = this.getRecord(selectedRows[0]);
});