Flot animating a vertical line from one point to other - javascript

I am stuck in a bit of a problem. You people might have seen an animated line which acts like a scanner in many apps. Well I ned something similar to that but I need it in a graph.
What I actually need is that I need to plt a vertical line which moves from one point to other automatically.
Let me give you a bit more explaination:
1. I have a button
2. I press the button and graph area appears.
3. On the graph area, a vertical line scrolls through the area as if it is scanning the area.
I am able to plot the line but it is coming out to be a little tilted. The logic behind that is provided below:
for(i=0;i<frequencyArray.length;i++){
myTestArray2.push([i,outFrequencyArray[i]]);
}
plot.setData([
{data:myTestArray2,lines:{fill:false,lineWidth:3},shadowSize:10}
]);
function setUpflot(){
// setup plot
//console.log("setUpflot");
var options = {
// series : { shadowSize: 0, splines: {show:true,lineWidth:1}},
series : { },
yaxis : { ticks: 5, tickColor:"rgba(148,129,151,0.5)", min: minGraphY, max:maxGraphY,show: true},
xaxis : { tickLength:0, show: false },
grid : { borderWidth:0,markings:[
{yaxis: { from: 200.0, to: 240.0 },color: "rgba(140,2,28,0.5)"}
]}
};

I put this together in response to a comment yesterday.
Fiddle here.
Produces:
plot = $.plot($("#placeholder"),
[ { data: someData} ], {
series: {
lines: { show: true }
},
crosshair: { mode: "x" }, // turn crosshair on
grid: { hoverable: true, autoHighlight: false },
yaxis: { min: -1.2, max: 1.2 }
});
crossHairPos = plot.getAxes().xaxis.min;
direction = 1;
setCrossHair = function(){
if (direction == 1){
crossHairPos += 0.5;
}
else
{
crossHairPos -= 0.5;
}
if (crossHairPos < plot.getAxes().xaxis.min){
direction = 1;
crossHairPos = plot.getAxes().xaxis.min;
}
else if (crossHairPos > plot.getAxes().xaxis.max)
{
direction = 0;
crossHairPos = plot.getAxes().xaxis.max;
}
plot.setCrosshair({x: crossHairPos})
setTimeout(setCrossHair,100);
}
// kick it off
setTimeout(setCrossHair,100);

var frequencyIndex = 0; //dynamic values stored intialised with 0.
var outFrequencyArray = [];
for(i=0;i<totalPoints;i++){
outFrequencyArray.push(minGraphY-1);
}
opd=Math.tan(Math.PI/2);
outFrequencyArray.splice(frequencyIndex,0,opd);
frequencyIndex++;
for(i=0;i<frequencyArray.length;i++){
myTestArray2.push([i,outFrequencyArray[i]]);
}
plot.setData([
{data:myTestArray2,lines:{fill:false,lineWidth:3},shadowSize:10}
]);
function setUpflot(){
// setup plot
//console.log("setUpflot");
var options = {
// series : { shadowSize: 0, splines: {show:true,lineWidth:1}},
series : { },
yaxis : { ticks: 5, tickColor:"rgba(148,129,151,0.5)", min: minGraphY, max:maxGraphY,show: true},
xaxis : { tickLength:0, show: false },
grid : { borderWidth:0,markings:[
{yaxis: { from: 200.0, to: 240.0 },color: "rgba(140,2,28,0.5)"}
]}
};

Related

Highcharts add new data to series after click

I'm trying to add a new point (to series data) on spline chart after clicking in the place where I'm clicked on the line. But point click event doesn't return xAxis, yAxis (only in pixels). I decide to calculate the difference between point pixels position and click, but point adds not on the click place. What I'm doing wrong? How to handle this?
My JS
var setDragStatus = function (status) {
document.getElementById('dragstatus').innerHTML = status;
};
Highcharts.chart('container', {
title: {
text: 'Spline Drag&Drop'
},
plotOptions: {
series: {
turboThreshold: 4,
minPointLength: 5,
dragDrop: {
draggableY: true,
dragMaxY: 1,
},
point: {
events: {
click: function (e) {
let pointPlotX = e.point.plotX
let pointPlotY = e.point.plotY
let pointX = e.point.x
let pointY = e.point.y
let clickX = e.chartX
let clickY = e.chartY
let pointDiffX = clickX / pointPlotX
let pointDiffY = clickY / pointPlotY
let newPointX = pointX * pointDiffX
let newPointY = pointDiffY * pointY
this.series.addPoint([newPointX, newPointY])
}
}
},
}
},
xAxis: {
reversed: false,
showFirstLabel: false,
showLastLabel: true
},
series: [
{
name: 'spline top',
data: [0, 0.3, 0.6, 1],
type: 'spline'
}
]
}
);
Result - https://jsfiddle.net/antiaf/1hfuyjbr/
To calculate x and y values you can use toValue Axis method:
plotOptions: {
series: {
...,
point: {
events: {
click: function(e) {
let series = this.series,
yAxis = series.yAxis,
xAxis = series.xAxis,
newPointX = xAxis.toValue(e.chartX),
newPointY = yAxis.toValue(e.chartY);
this.series.addPoint([newPointX, newPointY])
}
}
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/hg81o4ej/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Axis#toValue

Kendo UI chart: adjust label amount dynamically

I have a zoomable area chart and an x-axis label for every datapoint. When the chart loads, there is way too many labels, therefor I set the step option:
categoryAxis: {
name: 'CatAxis',
categories: graphLabels,
step: 30
}
But when the user zooms in, I need to decrease the amount of steps, otherwise no labels will be shown at all.
Therefor I subscribed to the zoomEnd event and calculate the desired amount of step:
function onZoomEnd(e) {
var xRange = e.axisRanges.CatAxis;
if (xRange) {
var diff = xRange.max - xRange.min;
var step = 1;
while (diff / step > 6) {
step++;
}
e.sender.setOptions({ categoryAxis: { labels: { step: step } } });
}
But setting the options here causes the chart to refresh and thereby losing its zoom level. The ultimate goal is to show a reasonable amount of labels without them overlapping or disappearing when zooming in and out. Any ideas how to achieve this?
you can maintain the zoom level of the chart using the following example from documentation
https://docs.telerik.com/kendo-ui/knowledge-base/maintain-pan-zoom-state
<button id="rebind">Rebind Chart</button>
<div id="chart"></div>
<script>
// Sample data
var data = [];
for (var i = 0; i < 100; i++) {
var val = Math.round(Math.random() * 10);
data.push({
category: "C" + i,
value: val
});
}
function createChart() {
var axisMin = 0;
var axisMax = 10;
function updateRange(e) {
var axis = e.sender.getAxis('axis')
var range = axis.range()
axisMin = range.min;
axisMax = range.max;
}
function restoreRange(e) {
e.sender.options.categoryAxis.min = axisMin;
e.sender.options.categoryAxis.max = axisMax;
}
$("#chart").kendoChart({
renderAs: "canvas",
dataSource: {
data: data
},
categoryAxis: {
name: "axis",
min: axisMin,
max: axisMax,
labels: {
rotation: "auto"
}
},
series: [{
type: "column",
field: "value",
categoryField: "category"
}],
pannable: {
lock: "y"
},
zoomable: {
mousewheel: {
lock: "y"
},
selection: {
lock: "y"
}
},
zoom: updateRange,
drag: updateRange,
dataBound: restoreRange
});
}
$("#rebind").click(function() {
$("#chart").data("kendoChart").dataSource.read();
});
$(document).ready(createChart);
</script>

In FlotCharts, how can I make the tooltips always visible?

As a newbee trying o study all of this, but just get pour information from ther friend google. Maybe I am doing the wrong question.
I folow this instructions in Stach Overflow, but no success,
Please teach-me if I am doing this wrong...
My graph is in real time, mimetizing one EGC, (a heart beat):
=> how to always show this "tooltips"(getRandomData3())? (not only when the mouse is over, but all the time)?
I realy apreciate any help ou tips. Thanks
here is my Data Series:
function getRandomData3() {
if (data3.length > 0)
data3 = data3.slice(1);
while (data3.length < totalPoints) {
if (flagGo==1){
instantFlag=200;
flagGo=2
}
else{
instantFlag=1000;
}
instantShowFlag = instantFlag;
data3.push(instantShowFlag);
}
// Zip the generated y values with the x values
var res = [];
for (var i = 0; i < data3.length; ++i) {
res.push([i, data3[i]])
}
// console.log(data1);
return res;
}
and how I put it on the graphics
var plot = $.plot("#placeholder", [{data: getRandomData1()}, {data: getRandomData2()}, {data: getRandomData3()}], {
series: {
shadowSize: 0 // Drawing is faster without shadows
},
yaxis: {
min: -50,
max: 250,
color: "#EDC240",
},
xaxis: {
show: false,
},
tooltip: {
show: true,
content: 'FLAG これはたとえばです',
shifts: {
x: 10,
y: -10,
}
},
grid: {
hoverable: true,
mouseActiveRadius: 30,
}
});
function update() {
plot.setData([{data: getRandomData1()}, {data: getRandomData2()}, {data: getRandomData3()}]);
plot.draw();
setTimeout(update, updateInterval);
}
update();
});
Thanks,

ChartJS New Lines '\n' in X axis Labels or Displaying More Information Around Chart or Tooltip with ChartJS V2

I'm using chart.js (V2) to try to build a bar chart that has more information available to user without having to hover over or click anywhere. I've provided two examples of how I hope to edit my chart.
Two edited versions of what I hope to achieve
As can be seen, I hope to place (somewhere), some extra information outside of the labels. I had hope that by adding '\n' to the labels I might have been able to get what I was looking for similar to option A.
Some edited code is provided blow:
var barChartData = {
labels: playerNames,
datasets: [{
label: 'Actual Score/Hour',
backgroundColor: "rgba(0, 128, 0,0.5)",
data: playerScores
}, {
label: 'Expected Score/Hour',
backgroundColor: "rgba(255,0,0,0.5)",
data: playerExpected
}]
};
function open_win(linktosite) {
window.open(linktosite)
}
canvas.onclick = function(evt){
var activePoints = myBar.getElementsAtEvent(evt);
console.log(activePoints);
linktosite = 'https://www.mytestsite.com/' + activePoints[1]['_model']['label'];
open_win(linktosite);
};
window.onload = function() {
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
title:{
display:true,
text:"Player Expected and Actual Score per Hour"
},
tooltips: {
mode: 'label'
},
responsive: true,
scales: {
xAxes: [{
stacked: false,
}],
yAxes: [{
stacked: false
}]
},
animation: {
onComplete: function () {
var ctx = this.chart.ctx;
ctx.textAlign = "center";
Chart.helpers.each(this.data.datasets.forEach(function (dataset) {
Chart.helpers.each(dataset.metaData.forEach(function (bar, index) {
// console.log("printing bar" + bar);
ctx.fillText(dataset.data[index], bar._model.x, bar._model.y - 10);
}),this)
}),this);
}
}
}
});
// Chart.helpers.each(myBar.getDatasetMeta(0).data, function(rectangle, index) {
// rectangle.draw = function() {
// myBar.chart.ctx.setLineDash([5, 5]);
// Chart.elements.Rectangle.prototype.draw.apply(this, arguments);
// }
// }, null);
};
At this point I'd be satisfied with having the extradata anywhere on the bar. Any help would be appreciated. Thanks~
Chart.js v2.1.5 allows for multi-line labels using nested arrays (v2.5.0 fixes it for radar graphs):
...
data: {
labels: [["Jake", "Active: 2 hrs", "Score: 1", "Expected: 127", "Attempts: 4"],
["Matt", "Active: 2 hrs", "Score: 4", "Expected: 36", "Attempts: 4"]],
...
However, this does mean that you will have to pre-calculate the label values.
var config = {
type: 'line',
data: {
labels: [["January","First Month","Jellyfish","30 of them"], ["February","Second Month","Foxes","20 of them"], ["March","Third Month","Mosquitoes","None of them"], "April", "May", "June", "July"],
datasets: [{
label: "My First dataset",
data: [65, 40, 80, 81, 56, 85, 45],
backgroundColor: "rgba(255,99,132,0.2)",
}, {
label: "My Second dataset",
data: [40, 80, 21, 56, 85, 45, 65],
backgroundColor: "rgba(99,255,132,0.2)",
}]
},
scales : {
xAxes : [{
gridLines : {
display : false,
lineWidth: 1,
zeroLineWidth: 1,
zeroLineColor: '#666666',
drawTicks: false
},
ticks: {
display:true,
stepSize: 0,
min: 0,
autoSkip: false,
fontSize: 11,
padding: 12
}
}],
yAxes: [{
ticks: {
padding: 5
},
gridLines : {
display : true,
lineWidth: 1,
zeroLineWidth: 2,
zeroLineColor: '#666666'
}
}]
},
spanGaps: true,
responsive: true,
maintainAspectRatio: true
};
var ctx = document.getElementById("myChart").getContext("2d");
new Chart(ctx, config);
<div class="myChart">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script>
<canvas id="myChart"></canvas>
</div>
If a label is an array as opposed to a string i.e. [["June","2015"], "July"] then each element is treated as a separate line. The appropriate calculations are made to determine the correct height and width, and rotation is still supported.
charJS version 2.7.2 used
this also works in https://github.com/jtblin/angular-chart.js
If you are using Chart.js v2.7.1, the above solution might not work.
The solution that actually worked for us was adding a small plugin right in the data and options level:
const config = {
type: 'bar',
data: {
// ...
},
options: {
// ...
},
plugins: [{
beforeInit: function (chart) {
chart.data.labels.forEach(function (label, index, labelsArr) {
if (/\n/.test(label)) {
labelsArr[index] = label.split(/\n/)
}
})
}
}]
};
A full description of how to fix this issue can be found here.
With Chart.js v2.1, you can write a chart plugin to do this
Preview
Script
Chart.pluginService.register({
beforeInit: function (chart) {
var hasWrappedTicks = chart.config.data.labels.some(function (label) {
return label.indexOf('\n') !== -1;
});
if (hasWrappedTicks) {
// figure out how many lines we need - use fontsize as the height of one line
var tickFontSize = Chart.helpers.getValueOrDefault(chart.options.scales.xAxes[0].ticks.fontSize, Chart.defaults.global.defaultFontSize);
var maxLines = chart.config.data.labels.reduce(function (maxLines, label) {
return Math.max(maxLines, label.split('\n').length);
}, 0);
var height = (tickFontSize + 2) * maxLines + (chart.options.scales.xAxes[0].ticks.padding || 0);
// insert a dummy box at the bottom - to reserve space for the labels
Chart.layoutService.addBox(chart, {
draw: Chart.helpers.noop,
isHorizontal: function () {
return true;
},
update: function () {
return {
height: this.height
};
},
height: height,
options: {
position: 'bottom',
fullWidth: 1,
}
});
// turn off x axis ticks since we are managing it ourselves
chart.options = Chart.helpers.configMerge(chart.options, {
scales: {
xAxes: [{
ticks: {
display: false,
// set the fontSize to 0 so that extra labels are not forced on the right side
fontSize: 0
}
}]
}
});
chart.hasWrappedTicks = {
tickFontSize: tickFontSize
};
}
},
afterDraw: function (chart) {
if (chart.hasWrappedTicks) {
// draw the labels and we are done!
chart.chart.ctx.save();
var tickFontSize = chart.hasWrappedTicks.tickFontSize;
var tickFontStyle = Chart.helpers.getValueOrDefault(chart.options.scales.xAxes[0].ticks.fontStyle, Chart.defaults.global.defaultFontStyle);
var tickFontFamily = Chart.helpers.getValueOrDefault(chart.options.scales.xAxes[0].ticks.fontFamily, Chart.defaults.global.defaultFontFamily);
var tickLabelFont = Chart.helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
chart.chart.ctx.font = tickLabelFont;
chart.chart.ctx.textAlign = 'center';
var tickFontColor = Chart.helpers.getValueOrDefault(chart.options.scales.xAxes[0].fontColor, Chart.defaults.global.defaultFontColor);
chart.chart.ctx.fillStyle = tickFontColor;
var meta = chart.getDatasetMeta(0);
var xScale = chart.scales[meta.xAxisID];
var yScale = chart.scales[meta.yAxisID];
chart.config.data.labels.forEach(function (label, i) {
label.split('\n').forEach(function (line, j) {
chart.chart.ctx.fillText(line, xScale.getPixelForTick(i + 0.5), (chart.options.scales.xAxes[0].ticks.padding || 0) + yScale.getPixelForValue(yScale.min) +
// move j lines down
j * (chart.hasWrappedTicks.tickFontSize + 2));
});
});
chart.chart.ctx.restore();
}
}
});
and then
...
data: {
labels: ["January\nFirst Month\nJellyfish\n30 of them", "February\nSecond Month\nFoxes\n20 of them", "March\nThird Month\nMosquitoes\nNone of them", "April", "May", "June", "July"],
...
Note - we assume that the maximum content of one line will fit between the ticks (i.e. that no rotation logic is needed. I'm sure it's possible to incorporate rotation logic too, but it would be a tad more complicated)
You should format the tooltips to not show the x axis label, or format it to show a shorter version of the label.
Fiddle - http://jsfiddle.net/m0q03wpy/

Highcharts - column chart redraw animation

I'm trying to update an existing data series with a new data array and invoke the redraw function when done. While this works perfectly, I'm not quite satisfied as I'd like to have a sort of grow/shrink transition. I have seen an example by Highcharts (fiddle around with the existing data set then click on the button "Set new data to selected series") but I can't replicate this behavior.
This is what code that I've written:
var series, newSeriesThreshold = this.chart.series.length * 2;
for (var i = 0; i < data.length; i += 2) {
series = {
name: this.data[i].title,
data: this.data[i].data,
color: this.data[i].color
};
if (i >= newSeriesThreshold) {
this.chart.addSeries(series, false);
} else {
var currentSeries = this.chart.series[i / 2];
currentSeries.setData(series.data, false);
}
}
this.chart.redraw();
These are the options when creating the chart:
var config = {
chart: {
renderTo: $(this.container).attr('id'),
type: this.settings.type,
animation: {
duration: 500,
easing: 'swing'
}
},
title: {
text: null
},
legend: {
enabled: this.settings.legend.show
},
tooltip: {
formatter: function() {
return this.x.toFixed(0) + ": <b>" + this.y.toString().toCurrency(0) + '</b>';
}
},
xAxis: {
title: {
text: this.settings.xaxis.title,
style: {
color: '#666'
}
}
},
yAxis: {
title: {
text: this.settings.yaxis.title,
style: {
color: '#666'
}
}
},
series: series,
plotOptions: {
column: {
color: '#FF7400'
}
},
credits: {
enabled: false
}
};
This yields an immediate update without transitioning effects. Any ideas what I might be doing wrong?
I have solved this problem by destroying and creating again the chart.
Here is the link on highcharts forum that helps me : http://forum.highcharts.com/highcharts-usage/animation-on-redraw-t8636/#p93199
The answer comes from the highcharts support team.
$(document).ready(function() {
var chartOptions = {
// Your chart options
series: [
{name: 'Serie 1' , color: '#303AFF', data: [1,1,1,1,1,1,1}
]
};
var chart = new Highcharts.Chart(chartOptions);
$("#my_button").click(function(){
chart.destroy();
chartOptions.series[0].data = [10,5,2,10,5,2,10];
chart = new Highcharts.Chart(chartOptions);
});
});
This remain a mystery. I managed to make the axis update which suggests that there is some kind of animation going on, but it's applied only to the axis, and not the columns.
In the end, I've settled with this behavior.
This might help:
var mychart = $("#mychart").highcharts();
var height = mychart.renderTo.clientHeight;
var width = mychart.renderTo.clientWidth;
mychart.setSize(width, height);
to update all charts
$(Highcharts.charts).each(function(i,chart){
var height = chart.renderTo.clientHeight;
var width = chart.renderTo.clientWidth;
chart.setSize(width, height);
});

Categories

Resources