Chart js sum of grouped bars - javascript

I have 3 different values for each grouped bar. I want to sum those 3 values and display the sum on top of each column - Σ59 and Σ89.
I'm testing code below which is not working correctly. Instead of column values, number 59 is displayed above every single column.
formatter: function(value, ctx) {
console.log(ctx.chart.data.datasets)
let sum = 0;
for (var i = 0; i < ctx.chart.data.datasets.length; i++) {
sum += parseInt(ctx.chart.data.datasets[i].data[0]);
}
return sum;
}

you can try something like this fiddle, but i did not format and position the labels as of now, you can do it as you wish.
"onComplete": function() {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
var sums = [0, 0, 0];
this.data.datasets.forEach(function(dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function(bar, index) {
var data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y);
sums[index] += data;
});
});
sums.forEach(function(v, i) {
ctx.fillText(v, 150*(i+1)+(i*50), 40);
});
}

The formatter is called for each datalabel, meaning for every bar. That's the reason why you get the same value on top of every bar.
Possible solutions would be either to plot an "invisible" bar for the combined value or check inside the formatter function if it is called for the centered bar. Then you could use mulitline labels to create a label which has the value for the current bar and the combined value as well.
Edit:
After thinking about it the easiest way would be to use mixed charts. You can just calculate your combined values for each group and add a chart for these values. For example you add a line chart with showLines: false.
new Chart('myMixedCharts', {
type: 'bar',
data: {
labels: ['foo', 'bar'],
datasets: [
{
label: "Value 1",
data: [12, 5]
},
{
label: "Value 2",
data: [7, 8]
},
{
label: "Group value",
data: [19, 13],
type: "line",
showLines: false
}
]
}
});
Or as jsFiddle

Related

Is there a way in a donut Chart.JS to show a % out of 100

I have a donut chart showing a number. However is there a way which the donut chart can be out of 100%, so the number I give in the data section: say 21, will show 21% complete out of 100?
Image to show desired outcome:
So the donut ring is greyed out and the coloured section is how much has been completed (or what number we allocate to the data section, I've been looking at the documentation and cannot see a way this can be done?
Code I have currently:
<canvas id="Chart1" style="width=5 height=5"></canvas>
<?php
$var = 3;
?>
var ctx = document.getElementById('Chart1').getContext('2d');
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'doughnut',
// The data for our dataset
data: {
labels: ['% Complete'],
datasets: [{
label: 'chart1',
backgroundColor: 'rgb(102, 178, 255)',
borderColor: 'rgb(102, 178, 255)',
// Below I just pull out 1 number from the db
data: [<?php echo $var ?>]
}]
},
});
My code outputs the below (so the 3 fills up the whole donut), whereas I would like it show 3% out of 100% complete.
Try passing data of [3, 97]. You're trying to use it as a loading indicator but it seems designed for showing 100% of things broken into parts.
If you pass simply [3], then that's 100% of your dataset
Create a two value dataset, like:
[percent_value, 100-percent_value]
Here's a full demo:
const originalDoughnutDraw = Chart.controllers.doughnut.prototype.draw;
Chart.helpers.extend(Chart.controllers.doughnut.prototype, {
draw: function() {
const chart = this.chart;
const {
width,
height,
ctx,
config
} = chart.chart;
const {
datasets
} = config.data;
const dataset = datasets[0];
const datasetData = dataset.data;
const completed = datasetData[0];
const text = `${completed}% completed`;
let x, y, mid;
originalDoughnutDraw.apply(this, arguments);
const fontSize = (height / 350).toFixed(2);
ctx.font = fontSize + "em Lato, sans-serif";
ctx.textBaseline = "top";
x = Math.round((width - ctx.measureText(text).width) / 2);
y = (height / 1.8) - fontSize;
ctx.fillStyle = "#000000"
ctx.fillText(text, x, y);
mid = x + ctx.measureText(text).width / 2;
}
});
var context = document.getElementById('myChart').getContext('2d');
var percent_value = 3;
var chart = new Chart(context, {
type: 'doughnut',
data: {
labels: ['Completed', 'Pending'],
datasets: [{
label: 'First dataset',
data: [percent_value, 100 - percent_value],
backgroundColor: ['#00baa6', '#ededed']
}]
},
options: {}
});
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
<canvas id="myChart"></canvas>

Stacked bar chart with (computed) average line in Plotly.js

I've got a (stacked) bar chart and I want an average line plotted on my chart.
Let's take this example:
var trace1 = {
x: ['giraffes', 'orangutans', 'monkeys'],
y: [20, 14, 23],
name: 'SF Zoo',
type: 'bar'
};
var trace2 = {
x: ['giraffes', 'orangutans', 'monkeys'],
y: [12, 18, 29],
name: 'LA Zoo',
type: 'bar'
};
var data = [trace1, trace2];
var layout = {barmode: 'stack'};
Plotly.newPlot('myDiv', data, layout, {showSendToCloud:true});
Result:
Expected output:
I've found a similar question, but in that case it was pretty easy to add a line with a 'fixed' value. In this case I've got a stacked bar chart nicolaskruchten/pivottable, so the user can easily drag and drop columns. That makes computing the average harder.
I can loop through all results and compute the average value, but since Plotly is very powerful and has something like aggregate functions, I feel like there should be a better way.
How can I add a (computed) average line to my (stacked) bar chart?
Plotly.js not provided any direct options for drawing average line.
But you can do this simple way.
//Find average value for Y
function getAverageY() {
allYValues = trace1.y.map(function (num, idx) {
return num + trace2.y[idx];
});
if (allYValues.length) {
sum = allYValues.reduce(function (a, b) {
return a + b;
});
avg = sum / allYValues.length;
}
return avg;
}
//Create average line in shape
var layout = {
barmode: 'stack',
shapes: [{
type: 'line',
xref: 'paper',
x0: 0,
y0: getAverageY(),
x1: 1,
y1: getAverageY(),
line: {
color: 'green',
width: 2,
dash: 'dot'
}
}]
};
Updated:
You need to update your graph after loading this drawing a average
line for any numbers of trace.
//Check graph is loaded
if (document.getElementById('myDiv')) {
//draw average line
drawAvgLine(document.getElementById('myDiv'))
}
function drawAvgLine(graph) {
var graphData = graph.data; //Loaded traces
//making new layout
var newLayout = {
barmode: 'stack',
shapes: [{
type: 'line',
xref: 'paper',
x0: 0,
y0: getAverageY(graphData),
x1: 1,
y1: getAverageY(graphData),
line: {
color: 'green',
width: 2,
dash: 'dot'
}
}]
};
//Update plot pass existing data
Plotly.update('myDiv', graphData, newLayout)
}
//Calculate avg value
function getAverageY(graphData) {
var total = [],
undefined;
for (var i = 0, n = graphData.length; i < n; i++) {
var arg = graphData[i].y
for (var j = 0, n1 = arg.length; j < n1; j++) {
total[j] = (total[j] == undefined ? 0 : total[j]) + arg[j];
}
}
return total.reduce(function (a, b) {
return a + b;
}) / total.length;
}

Chart.js — drawing an arbitrary vertical line

How can I draw an vertical line at a particular point on the x-axis using Chart.js?
In particular, I want to draw a line to indicate the current day on a LineChart. Here's a mockup of the chart:
http://i.stack.imgur.com/VQDWR.png
Update - this answer is for Chart.js 1.x, if you are looking for a 2.x answer check the comments and other answers.
You extend the line chart and include logic for drawing the line in the draw function.
Preview
HTML
<div>
<canvas id="LineWithLine" width="600" height="400"></canvas>
</div>
Script
var data = {
labels: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"],
datasets: [{
data: [12, 3, 2, 1, 8, 8, 2, 2, 3, 5, 7, 1]
}]
};
var ctx = document.getElementById("LineWithLine").getContext("2d");
Chart.types.Line.extend({
name: "LineWithLine",
draw: function () {
Chart.types.Line.prototype.draw.apply(this, arguments);
var point = this.datasets[0].points[this.options.lineAtIndex]
var scale = this.scale
// draw line
this.chart.ctx.beginPath();
this.chart.ctx.moveTo(point.x, scale.startPoint + 24);
this.chart.ctx.strokeStyle = '#ff0000';
this.chart.ctx.lineTo(point.x, scale.endPoint);
this.chart.ctx.stroke();
// write TODAY
this.chart.ctx.textAlign = 'center';
this.chart.ctx.fillText("TODAY", point.x, scale.startPoint + 12);
}
});
new Chart(ctx).LineWithLine(data, {
datasetFill : false,
lineAtIndex: 2
});
The option property lineAtIndex controls which point to draw the line at.
Fiddle - http://jsfiddle.net/dbyze2ga/14/
Sharing my solution for chartjs.org version 2.5. I wanted to use a plugin, to make the implementation reusable.
const verticalLinePlugin = {
getLinePosition: function (chart, pointIndex) {
const meta = chart.getDatasetMeta(0); // first dataset is used to discover X coordinate of a point
const data = meta.data;
return data[pointIndex]._model.x;
},
renderVerticalLine: function (chartInstance, pointIndex) {
const lineLeftOffset = this.getLinePosition(chartInstance, pointIndex);
const scale = chartInstance.scales['y-axis-0'];
const context = chartInstance.chart.ctx;
// render vertical line
context.beginPath();
context.strokeStyle = '#ff0000';
context.moveTo(lineLeftOffset, scale.top);
context.lineTo(lineLeftOffset, scale.bottom);
context.stroke();
// write label
context.fillStyle = "#ff0000";
context.textAlign = 'center';
context.fillText('MY TEXT', lineLeftOffset, (scale.bottom - scale.top) / 2 + scale.top);
},
afterDatasetsDraw: function (chart, easing) {
if (chart.config.lineAtIndex) {
chart.config.lineAtIndex.forEach(pointIndex => this.renderVerticalLine(chart, pointIndex));
}
}
};
Chart.plugins.register(verticalLinePlugin);
Usage is simple then:
new Chart(ctx, {
type: 'line',
data: data,
label: 'Progress',
options: options,
lineAtIndex: [2,4,8],
})
The code above inserts red vertical lines at positions 2,4 and 8, running through points of first dataset at those positions.
I'd highly recommend to use the Chartjs-Plugin-Annotation.
An example can be found at CodePen
var chartData = {
labels: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"],
datasets: [
{
data: [12, 3, 2, 1, 8, 8, 2, 2, 3, 5, 7, 1]
}
]
};
window.onload = function() {
var ctx = document.getElementById("canvas").getContext("2d");
new Chart(ctx, {
type: "line",
data: chartData,
options: {
annotation: {
annotations: [
{
type: "line",
mode: "vertical",
scaleID: "x-axis-0",
value: "MAR",
borderColor: "red",
label: {
content: "TODAY",
enabled: true,
position: "top"
}
}
]
}
}
});
};
Have a look here for more Details: https://stackoverflow.com/a/36431041
I had to go through the trouble of figuring out how to do something similar with ChartJS 2.0 so I thought I would share.
This is based on the new way of overriding a chart prototype as explained here: https://github.com/chartjs/Chart.js/issues/2321
var ctx = document.getElementById('income-chart');
var originalDraw = Chart.controllers.line.prototype.draw;
Chart.controllers.line.prototype.draw = function (ease) {
originalDraw.call(this, ease);
var point = dataValues[vm.incomeCentile];
var scale = this.chart.scales['x-axis-0'];
// calculate the portion of the axis and multiply by total axis width
var left = (point.x / scale.end * (scale.right - scale.left));
// draw line
this.chart.chart.ctx.beginPath();
this.chart.chart.ctx.strokeStyle = '#ff0000';
this.chart.chart.ctx.moveTo(scale.left + left, 0);
this.chart.chart.ctx.lineTo(scale.left + left, 1000000);
this.chart.chart.ctx.stroke();
// write label
this.chart.chart.ctx.textAlign = 'center';
this.chart.chart.ctx.fillText('YOU', scale.left + left, 200);
};
With chart.js 3.8.0 I've used a combo between line/bar chart with timeline (xAxis) and percentage (yAxis). See docs
The dataset configuration provides a option to set the maxBarThickness (I've applied 2) and then apply the max value of the y-axis on each data entry of the bar chart.
Example of dataset configuration:
datasets: [
{
type: 'line'
data: [
{x: "2022-07-18", y: 10},
{x: "2022-07-19", y: 60},
{x: "2022-07-20", y: 30}
],
....
},
{
type: 'bar',
data: [
{x: "2022-07-19", y: 100}
],
maxBarThickness: 2,
...
}
]
Example of the output:
Here's a pen that achieves a similar effect without the chartjs-plugin-annotation, or hacking how Chart.js renders, or any other plugins: https://codepen.io/gkemmey/pen/qBWZbYM
Approach
Use a combo bar / line chart, and use the bar chart to draw the vertical lines.
Use two y-axes: one for the bar chart (which we don't display), and one for all your other line chart datasets.
Force the bar chart y-axes to min: 0 and max: 1. Anytime you want to draw a vertical line, add a data object like { x: where_the_line_goes, y: 1 } to your bar chart dataset.
The pen also adds some custom data to the bar chart dataset and a legend filter and label callback to exclude the bar chart dataset from the legend, and control the label on the vertical line.
Pros
No other dependencies. No custom monkey patching / extending.
The annotations plugin doesn't seem to be actively maintained. For instance, atm, their event handlers throw an error about "preventing default on passive events"
Maybe a pro: The annotations plugin always shows the labels of lines drawn, and you have to use their event callbacks to get a show-on-hover effect. Chart.js tooltips show on hover by default.
Cons
We're adding custom data in the dataset config, and hoping it doesn't conflict with anything Chart.js is doing. It's data Chart.js doesn't expect to be there, but as of 2.8, also doesn't break it.
Enhanced version of #Tomáš Dvořák answer
Supports:
custom text for labels
custom color for line+label
custom alignment for labels
custom X/Y offset for labels
const verticalLinePlugin = {
getLinePosition: function (chart, pointIndex) {
const meta = chart.getDatasetMeta(0); // first dataset is used to discover X coordinate of a point
const data = meta.data;
return data[pointIndex]._model.x;
},
renderVerticalLine: function (chartInstance, pointIndex, label, color, alignment, xOffset, yOffset) {
const lineLeftOffset = this.getLinePosition(chartInstance, pointIndex);
const scale = chartInstance.scales['y-axis-0'];
const context = chartInstance.chart.ctx;
if (xOffset == undefined) xOffset = 0;
if (yOffset == undefined) yOffset = 0;
// render vertical line
context.beginPath();
context.strokeStyle = color;
context.moveTo(lineLeftOffset, scale.top);
context.lineTo(lineLeftOffset, scale.bottom);
context.stroke();
// write label
context.fillStyle = color;
context.textAlign = alignment;
context.fillText(label, lineLeftOffset + xOffset, (scale.bottom - scale.top) / 2 + scale.top + yOffset);
},
afterDatasetsDraw: function (chart, easing) {
if (chart.config.lineAtIndex) {
labelIndex = 0;
chart.config.lineAtIndex.forEach((pointIndex) => {
if (chart.config.verticalLinesLabels != undefined) { // if array of labels exists...
label = chart.config.verticalLinesLabels[labelIndex]; // chart.config.verticalLinesLabels must contain all elements; use elements ="" for lines not requiring labels
color = chart.config.verticalLinesColors[labelIndex]; // chart.config.verticalLinesColors must contain all elements
alignment = chart.config.verticalLinesAlignments[labelIndex]; // chart.config.verticalLinesAlignments must contain all elements
xOff = chart.config.verticalLinesX[labelIndex]; // chart.config.verticalLinesX must contain all elements
yOff = chart.config.verticalLinesY[labelIndex]; // chart.config.verticalLinesY must contain all elements
} else {
label = "";
}
this.renderVerticalLine(chart, pointIndex, label, color, alignment, xOff, yOff)
labelIndex++;
});
}
}
};
Chart.plugins.register(verticalLinePlugin);
Usage:
myChart.config.verticalLinesLabels = ["aaa", "bbb", "ddd"];
myChart.config.verticalLinesColors = ["#FF0000", 'rgb(0,255,0)', 'rgba(0,0,255,0.5)'];
myChart.config.verticalLinesAlignments = ["left", "center", "right"]; // Set label aligment (note: it is inverted because referred to line, not to label)
myChart.config.verticalLinesX = [10,5,0]; // Set label X offset
myChart.config.verticalLinesY = [10,5,0]; // Set label Y offset
myChart.config.lineAtIndex = [10,30,50]; // Mandatory to enable all previous ones
myChart.update()

Style specific bar column with Flot

I'm working with Flot to create a bar chart. However, I need to add special styling to certain columns. Is this possible at all?
My HTML looks like this:
<div id="monthly-usage" style="width: 100%; height: 400px;"></div>
And my JS like this:
somePlot = null;
$(function() {
//Data from this year and last year
var thisYear = [
[3, 231.01],
[4, 219.65],
[5, 222.47],
[6, 223.09],
[7, 248.43],
[8, 246.22]
];
var lastYear = [
[3, 171.7],
[4, 130.62],
[5, 163.03],
[6, 166.46],
[7, 176.16],
[8, 169.04]
];
var usageData = [{
//Usage this year
label: "2014",
data: thisYear,
bars: {
show: true,
barWidth: .3,
fill: true,
lineWidth: 0,
order: 1,
fillColor: 'rgba(194, 46, 52, .85)'
},
color: '#c22e34'
}, {
//Usage last year to compare with current usage
label: "2013",
data: lastYear,
bars: {
show: true,
barWidth: .3,
fill: true,
lineWidth: 0,
order: 2,
fillColor: 'rgba(73, 80, 94, .85)'
},
color: '#49505e'
}];
//X-axis labels
var months = [
[0, "Jan"],
[1, "Feb"],
[2, "Mar"],
[3, "Apr"],
[4, "Maj"],
[5, "Jun"],
[6, "Jul"],
[7, "Aug"],
[8, "Sep"],
[9, "Okt"],
[10, "Nov"],
[11, "Dec"]
];
//Draw the graph
somePlot = $.plot(('#monthly-usage'), usageData, {
grid: {
color: '#646464',
borderColor: 'transparent',
hoverable: true
},
xaxis: {
ticks: months,
color: '#d4d4d4'
},
yaxis: {
tickSize: 50,
tickFormatter: function(y, axis) {
return y + " kWh";
}
},
legend: {
show: false
}
});
var ctx = somePlot.getCanvas().getContext("2d"); // get the context from plot
var data = somePlot.getData()[0].data; // get your series data
var xaxis = somePlot.getXAxes()[0]; // xAxis
var yaxis = somePlot.getYAxes()[0]; // yAxis
var offset = somePlot.getPlotOffset(); // plots offset
var imageObj = new Image(); // create image
imageObj.onload = function() { // when finish loading image add to canvas
xPos = xaxis.p2c(data[4][0]) + offset.left;
yPos = yaxis.p2c(data[4][1]) + offset.top;
ctx.drawImage(this, xPos, yPos);
xPos = xaxis.p2c(data[5][0]) + offset.left;
yPos = yaxis.p2c(data[5][1]) + offset.top;
ctx.drawImage(this, xPos, yPos);
};
imageObj.src = 'path/to/file.png'; // set it's source to kick off load
});
});
Optimally, I would like to insert an icon in bar 5 and 6 that warns the user. Alternatively, I'd like to change the color of bars 5 and 6. Any ideas on how to fix this?
EDIT: I've updated my JS according to Mark's answer which works.
#Mark, how can I position the images correctly. They are a bit off. I need the image inside the red bar and not besides the bar. I'm trying to finetune this but it doesn't seem as if I can use for instance "0.5". I use side by side bars which is different from your version.
xPos = xaxis.p2c(data[4][0]) + offset.left;
yPos = yaxis.p2c(data[4][1]) + offset.top;
You can't do exactly what you ask with standard options, but there are a couple of possible approaches:
Write your own draw method and use the hooks to install it in place of the standard flot drawing code. This obviously entails a lot of work, but you'll have complete control over how to render your data. (That said, I wouldn't recommend it.)
Break your data into two different data sets. One data set would have dummy values (e.g. 0, or whatever your minimum is) for bars 5 and 6. The second data set would have dummy values for all bars except 5 and 6. You could then style the "two" data sets independently, giving each, for example a different color. Graph the two sets as a stacked bar chart with whatever additional styling tweaks are appropriate for your chart.
(As a FYI, there's a fair bit of information and examples at jsDataV.is. Look at the "Book" section; chapter 2 is dedicated to flot.)
flot gives you access to the HTML5 Canvas it's drawing on; so you just add your icon on there yourself. Borrowing from my own answer here.
var ctx = somePlot.getCanvas().getContext("2d"); // get the context from plot
var data = somePlot.getData()[0].data; // get your series data
var xaxis = somePlot.getXAxes()[0]; // xAxis
var yaxis = somePlot.getYAxes()[0]; // yAxis
var offset = somePlot.getPlotOffset(); // plots offset
$.get("someImage.txt", function(img) { // grad some image, I'm loading it from a base64 resource
var imageObj = new Image(); // create image
imageObj.onload = function() { // when finish loading image add to canvas
var xPos = xaxis.p2c(data[4][0]) + offset.left;
var yPos = yaxis.p2c(data[4][2]) + offset.top;
ctx.drawImage(this, xPos, yPos);
xPos = xaxis.p2c(data[5][0]) + offset.left;
yPos = yaxis.p2c(data[5][3]) + offset.top;
ctx.drawImage(this, xPos, yPos);
};
imageObj.src = img; // set it's source to kick off load
});
Example here.
Looks like:

How can I make highlighted points stay after regraphing using flot?

Currently, I have a plot that supports "lockable" points. I register a plotclick event, highlight the point, and display a tooltip that I give the id of "lockedPoint" + item.dataindex. I also have a zoom feature that uses jquery.flot.selection.js. By using this, I modify my x and y axis maximums and minimums, and I replot my data (essentially throwing away the old data). I am trying to preserve the "locked points" when zooming.
One solution I have thought of is when gathering my data, I can specifically push the point into the correct place in the series that it needs to be if it is within range of the zoom and then highlight the point. However, this does not seem to be working correctly.
I store the data about "locked points" in an associative array initialized like this.
for (var i = 1; i < 5; i++){
lockedPoints["Series " + i] = [];
}
Then I allow a maximum of three items to be pushed onto each array (max of three lockable points per series). I would replace the point in the array with the new highlighted point (I believe the only thing that would change would be the dataindex). Is it possible that I could make points survive zooming by pushing them into the data series when gathering data?
function gatherData(kElement, a0Element){
//PRE: kElement is the id of the element containing the rate constant, and a0Element is the id of the element
// containing the molarity
//POST: FCTVAL is a data series in the format of {data: data, lines: {show: true}, color: "color", label: "label"}
var xData = []; //x-coordinates
var yData = []; //y-coordinates
var data = []; //array of coordinate pairs
var startingPoint; //least x-value to graph
var finishingPoint; //greatest x-value to graph
var range; //range of x-values
var interval; //value to evenly space x-values for calculations
var current; //current value of x-coordinate for which we are
// calculating a y-value
var labelParent; //parent node of x-axis labels
var k; //rate constant value
var molarValue; //molarity value
var result; //result of the rate equation
numXPoints = 1001;
if (document.getElementById("logCheck").value == "On"){ //graph logarithmically
logarithmic = true;
}
else{ //graph decay
logarithmic = false;
}
if (document.getElementById("blackWhite").value == "On"){
blackWhite = true;
}
else{
blackWhite = false;
}
k = document.getElementById(kElement).value;
molarValue = document.getElementById(a0Element).value;
startingPoint = minX; //we will say time starts at 0 always for this plot
finishingPoint = maxX;
range = finishingPoint - startingPoint; //calculated range for determining points to plot
interval = range / numXPoints; //we will graph numXPoints points
current = startingPoint;
result = molarValue * Math.pow(Math.E, (-k * current));
if (logarithmic){ //for logarithmic calculations
result = Math.log(result);
}
if (result > maxValue){ //store largest y-value
maxValue = result;
}
for (var i = 0; i < numXPoints; i++){ //store x-values and calculated y-values
// and find max y-value
xData[i] = current;
yData[i] = result;
current += interval;
result = molarValue * Math.pow(Math.E, (-k * current));
if (logarithmic){ //for logarithmic calculations
result = Math.log(result);
}
if (yData[i] > maxValue){ //store largest y-value
maxValue = yData[i];
}
if (yData[i] < minValue && minValue > -400){ //store smallest y-value
minValue = yData[i];
}
}
for (var i = 0; i < numXPoints; i++){ //combine coordinates into one series
data[i] = [xData[i], yData[i]];
}
//modified jquery.flot.js to support dashed line hover.
//values modified were pointRadius and radius in the drawPointHighlight method.
if (blackWhite == true){
switch(kElement){
case "kValue1":
return {points:{show: true, radius: 0}, data: data, lines:{show: true}, color: "black", label: "Series 1", shadowSize: 0};
break;
case "kValue2":
return {points:{show: true, radius: 0}, data: data, dashes:{show: true, dashLength: 2}, color: "black", label: "Series 2", shadowSize: 0};
break;
case "kValue3":
return {points:{show: true, radius: 0}, data: data, dashes:{show: true, dashLength: 10}, color: "black", label: "Series 3", shadowSize: 0};
break;
case "kValue4":
return {points:{show: true, radius: 0}, data: data, dashes:{show: true, dashLength: 20}, color: "black", label: "Series 4", shadowSize: 0};
break;
}
}
else{
switch (kElement){ //return proper object to match flot graph description
case "kValue1":
return {points:{show: false, radius: 0}, data: data, lines:{show: true}, color: "red", label: "Series 1"};
break;
case "kValue2":
return {points:{show: false, radius: 0}, data: data, lines:{show: true}, color: "blue", label: "Series 2"};
break;
case "kValue3":
return {points:{show: false, radius: 0}, data: data, lines:{show: true}, color: "green", label: "Series 3"};
break;
case "kValue4":
return {points:{show: false, radius: 0}, data: data, lines:{show: true}, color: "gold", label: "Series 4"};
break;
}
}
}
I can find a way to deal with the tooltip removal, but highlighting the same point is the most trivial part.
If you use a combination of setupGrid and draw, the highlights will persist between redraws and you won't need to manually reapply (like you would if you re-init).
Also, to manipulate the data between re-draws (say on the zoom selection), use a combination of getData and setData:
$("#flot_chart").bind("plotselected", function (event, ranges) {
var fr = ranges.xaxis.from;
var to = ranges.xaxis.to;
$.each(plot.getXAxes(), function(_, axis) {
var opts = axis.options;
opts.min = fr;
opts.max = to
});
//pad data points, so the hover effect doesn't look spotty
var series = plot.getData(); // get series
series[0].data = []; // clear it out
for (var i = fr; i < to; i+=(to-fr)/100){
series[0].data.push([i,Math.sin(i)]); // push in data with a suitable increment to i
}
plot.setData(series); // set the new data
plot.setupGrid(); // redo the grid
plot.draw(); // redraw the plot
plot.clearSelection();
});
Here's a fiddle example.

Categories