Straight-lines chart with dynamic data (currently using graphael lib) - javascript

I am trying to build a dynamically fed (data) straight lines chart. I built a prototype using graphael.
Here is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Line Charts</title>
<script src="raphael.js"></script>
<script src="g.raphael.js"></script>
<script src="g.line.js"></script>
<script language="JavaScript" type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
window.onload = function () {
var r = Raphael("holder");
var yAxisTags = ["A","B","C","D"];
var xData = [
[2000,2015],//hack line, transparent; used to specify the range of the axis
[2008,2014],[2004,2005],[2009,2010],[2000,2007],[2000,2014],[2010,2012]
];
var yData = [
[1, 1],//y coordinates of hack line
[0, 0],[1, 1],[1, 1],[2, 2],[3, 3],[0,0],
[0, 0]//hack line, transparent.Used to be able to draw straight lines
];
var colors = [
'transparent',//line 1
'red','green','green','purple','turquoise','black',
'transparent'];//'transparent' IS A MUST, a hack to make it have a straight line
var options = {
nostroke: false,
gutter: 90,
axis: "0 0 1 1",
symbol: "circle",
axisxstep:10,
axisystep:3,
colors: colors
};
var lines = r.linechart(100, 10, 700, 300,xData,yData,options);
// AXIS (x and y) have values but do not drawn the lines
lines.axis[0].attr([{stroke: false}]);
lines.axis[1].attr([{stroke: false}]);
// Thickness of symbols (ie dots)
lines.symbols.attr({ r: 4 });
// Animate dots on first load
lines.animate({"stroke-width": 1}, 1000);//ALL lines,1000 is animation time
// Set text for Y axis coordinates (instead of numbers)
$.each(lines.axis[1].text.items, function(index, label) {
this.attr("text", yAxisTags[index]);
});
};
</script>
</head>
<body>
<div id="holder" style="width:50%"></div>
</body>
</html>
And here is how it looks like:
So basically I want a time related (jumps +2 years from point to point) line chart graph with labels on Y-axis, that is made by drawing straight lines and to which dynamic data is being fed. The current code works with this specific configuration only but once i start modifying the data, the display is not accurate anymore:
x-axis (time axis) gets buggy and time doesn't jump +2 years
if there is a large difference in between two years (2 X coordinates), the line is drawn as a dot
will have to modify axisxstep and axisxstep (don't understand how the logic behind these works to be honest)
etc..
Is there a technique/hack around to make my desired line chart concept work with dynamic data using graphael? or it is not feasible with this library?

For anyone stuck with this same scenario:
Since I am using AngularJS, I ended up using angular-google-chart.
It is a directive wrapper around google chart; it is stable and straightforward to use.

Related

Plotly.js: how to make markers only show when zoomed in (range slider with time on x-axis)

I'm using Plotly.js (javascript plotly) to configure a line chart that has a range slider and has dates on the x-axis (as in Range Slider and Selector | JavaScript | Plotly and in the snippet below). When you zoom in, I want the line chart to have dots at each data point (aka, mode: 'lines+markers'). When you zoom out, the dots look too crowded because they are very close together. So, I want the dots to disappear ( mode: 'lines') when zoomed in to 30 day's worth of data or less.
Is it possible to add markers to the chart only when zoomed in to a range span of 30 days or less? For example, when looking at an x-axis range of more than a week, the mode of the chart should be ‘lines’ but when zoomed in such that the x-axis’s range spans 30 days or less, the mode should be ‘lines+marker’.
I’m not certain the best language to ask the question, but I’m seeking a way to find a “hook” into the chart’s x-axis range. Since I’ve not defined the range (it’s managed instead via the range slider), how do I get my javascript to say “if the range[1] - range[0] is > 30 days, make mode = 'lines'; else if range[1] - range[0] is not > 30 days, make mode = 'lines+markers'.
// Generate 500 random numbers for Y axis
var randoms = [375438,375436,375434,375430,375428,375428,375428,375428,375422,375413,375412,375408,375405,375405,375405,375403,375393,375383,375380,375373,375373,375373,375375,375374,375371,375371,375367,375367,375367,375364,375348,375330,375325,375324,375324,375324,375318,375301,375295,375276,375254,375254,375254,375251,375243,375225,375209,375203,375221,375221,375221,375205,375183,375172,375153,375153,375153,375147,375130,375114,375094,375083,375083,375083,375083,375067,375050,375028,375023,375023,375021,375027,375008,374992,374988,374967,374967,374967,374971,374955,374938,374921,374898,374898,374896,374893,374873,374861,374840,374828,374828,374835,374835,374827,374809,374798,374772,374773,374773,374773,374761,374748,374738,374738,374738,374738,374749,374749,374729,374718,374717,374717,374717,374713,374728,374714,374705,374697,374697,374697,374702,374682,374668,374654,374637,374636,374636,374637,374637,374637,374622,374622,374622,374622,374624,374611,374604,374597,374592,374592,374592,374597,374588,374582,374573,374579,374579,374579,374579,374579,374572,374576,374570,374570,374570,374570,374559,374559,374567,374546,374546,374546,374552,374542,374530,374527,374505,374505,374505,374486,374467,374451,374450,374439,374439,374439,374433,374422,374429,374424,374373,374373,374373,374376,374371,374371,374358,374350,374350,374350,374356,374340,374348,374341,374307,374307,374307,374311,374318,374299,374282,374272,374272,374272,374271,374265,374238,374234,374224,374224,374223,374215,374199,374180,374171,374171,374171,374171,374170,374175,374168,374089,374089,374089,374089,374089,374089,374089,374089,374089,374089,374089,374089,374089,374082,374102,374073,374073,374075,374105,374094,374076,374051,374051,374051,374043,374030,374021,374029,374029,374029,374029,374028,374008,373997,373994,373977,373977];
// Make an array 1 - 500 for X axis
var xrange = ["2021-05-29","2021-05-28","2021-05-27","2021-05-26","2021-05-25","2021-05-24","2021-05-23","2021-05-22","2021-05-21","2021-05-20","2021-05-19","2021-05-18","2021-05-17","2021-05-16","2021-05-15","2021-05-14","2021-05-13","2021-05-12","2021-05-11","2021-05-10","2021-05-09","2021-05-08","2021-05-07","2021-05-06","2021-05-05","2021-05-04","2021-05-03","2021-05-02","2021-05-01","2021-04-30","2021-04-29","2021-04-28","2021-04-27","2021-04-26","2021-04-25","2021-04-24","2021-04-23","2021-04-22","2021-04-21","2021-04-20","2021-04-19","2021-04-18","2021-04-17","2021-04-16","2021-04-15","2021-04-14","2021-04-13","2021-04-12","2021-04-11","2021-04-10","2021-04-09","2021-04-08","2021-04-07","2021-04-06","2021-04-05","2021-04-04","2021-04-03","2021-04-02","2021-04-01","2021-03-31","2021-03-30","2021-03-29","2021-03-28","2021-03-27","2021-03-26","2021-03-25","2021-03-24","2021-03-23","2021-03-22","2021-03-21","2021-03-20","2021-03-19","2021-03-18","2021-03-17","2021-03-16","2021-03-15","2021-03-14","2021-03-13","2021-03-12","2021-03-11","2021-03-10","2021-03-09","2021-03-08","2021-03-07","2021-03-06","2021-03-05","2021-03-04","2021-03-03","2021-03-02","2021-03-01","2021-02-28","2021-02-27","2021-02-26","2021-02-25","2021-02-24","2021-02-23","2021-02-22","2021-02-21","2021-02-20","2021-02-19","2021-02-18","2021-02-17","2021-02-16","2021-02-15","2021-02-14","2021-02-13","2021-02-12","2021-02-11","2021-02-10","2021-02-09","2021-02-08","2021-02-07","2021-02-06","2021-02-05","2021-02-04","2021-02-03","2021-02-02","2021-02-01","2021-01-31","2021-01-30","2021-01-29","2021-01-28","2021-01-27","2021-01-26","2021-01-25","2021-01-24","2021-01-23","2021-01-22","2021-01-21","2021-01-20","2021-01-19","2021-01-18","2021-01-17","2021-01-16","2021-01-15","2021-01-14","2021-01-13","2021-01-12","2021-01-11","2021-01-10","2021-01-09","2021-01-08","2021-01-07","2021-01-06","2021-01-05","2021-01-04","2021-01-03","2021-01-02","2021-01-01","2020-12-31","2020-12-30","2020-12-29","2020-12-28","2020-12-27","2020-12-26","2020-12-25","2020-12-24","2020-12-23","2020-12-22","2020-12-21","2020-12-20","2020-12-19","2020-12-18","2020-12-17","2020-12-16","2020-12-15","2020-12-14","2020-12-13","2020-12-11","2020-12-10","2020-12-09","2020-12-08","2020-12-07","2020-12-06","2020-12-05","2020-12-04","2020-12-03","2020-12-02","2020-12-01","2020-11-16","2020-11-15","2020-11-14","2020-11-13","2020-11-12","2020-11-11","2020-11-10","2020-11-09","2020-11-08","2020-11-07","2020-11-06","2020-11-05","2020-11-04","2020-11-03","2020-11-02","2020-11-01","2020-10-31","2020-10-30","2020-10-29","2020-10-28","2020-10-27","2020-10-26","2020-10-25","2020-10-24","2020-10-23","2020-10-22","2020-10-21","2020-10-20","2020-10-19","2020-10-18","2020-10-17","2020-10-16","2020-10-15","2020-10-14","2020-10-13","2020-10-12","2020-10-11","2020-10-10","2020-10-09","2020-10-08","2020-10-07","2020-10-06","2020-10-05","2020-10-04","2020-10-03","2020-10-02","2020-10-01","2020-09-30","2020-09-29","2020-09-28","2020-09-27","2020-09-26","2020-09-25","2020-09-24","2020-09-23","2020-09-22","2020-09-21","2020-09-20","2020-09-19","2020-09-18","2020-09-17","2020-09-16","2020-09-15","2020-09-14","2020-09-13","2020-09-12","2020-09-11","2020-09-10","2020-09-09","2020-09-08","2020-09-07","2020-09-06","2020-09-05","2020-09-04","2020-09-03","2020-09-02","2020-09-01","2020-08-31"]
var trace = {
x: xrange,
y: randoms,
mode: 'lines+markers'
};
var layout = {
title: 'Time series with range slider and too many markers when zoomed out',
height: 400,
xaxis: {
rangeslider: {}
},
yaxis: {
fixedrange: true
}
};
var data = [trace];
Plotly.newPlot('myDiv', data, layout);
<body>
<div id="myDiv"></div>
<script src="https://cdn.plot.ly/plotly-latest.min.js" crossorigin="anonymous"></script>
</body>
Thanks in advance!

How do I pass the whole div to XEPOnline.js library and not just the first svg element?

I am using css2pdf#cloudformatter to export my plotly.js svg to pdf. It works nicely, but it does not export the colorbar of the heatmap. I am using the "srctype:'svg'" option to save the svg in exactly the format as it is on my website. Please have a look at the fiddle http://jsfiddle.net/rk9540x5/4/
Here is the script:
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script src="http://www.cloudformatter.com/Resources/Pages/CSS2Pdf/Script/xeponline.jqplugin.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<body>
<br><br>
<!-- Source and on-click event for plotly.js -->
<div id="plotly_chart" style="width: 90%; height: 270px"></div>
<button onclick="return xepOnline.Formatter.Format('plotly_chart',{render:'download',srctype:'svg' });">Get PDF</button>
<script type="text/javascript">
Chart = document.getElementById('plotly_chart');
var data = [
{
z: [[1, 20, 30], [20, 1, 60], [30, 60, 1]],
type: 'heatmap'
}
];
Plotly.newPlot('plotly_chart', data);
</script>
I did test it without the "srctype:'svg'" option, and this exports also the colorbar together with the plot, but the output does not look like the plot on the webpage anymore: the colorbar gets plotted below the heatmap. This suggests that css2pdf recognizes the div as two separate svg elements - one for the heatmap, and the other one for the colorbar.
It also says on the cloudformatter.com homepage (http://www.cloudformatter.com/CSS2Pdf.APIDoc.Usage) that "if srctype:'svg' option is used, the first svg element in the containing div will be formatted alone". How do I get around this? Is there any way to move the colorbar svg element into the heatmap svg element? Here is an image of the DOM - you can see that there are two different svg#s, "infolayer" representing the colorbar svg.
I already tried the following to add the colorbar to the plotly chart, but it does not help:
var colorbar = {
title: test,
titlefont: {
size: 12,
},
titleside: "top",
thickness: 20,
nticks: ticknumber,
tickfont: {
size:10.5
},
outlinewidth: 0,
xpad: 1,
ypad:3
};
Plotly.newPlot('plotly_chart', data).append("colorbar");
Thanks for helping with this issue!

chart.js Line chart with different background colors for each section

Lets say I have a Line chart with mon-fri for 4 weeks.
I want that these 4 weeks are diveded in sections. I want the first monday to friday have a white background color.
The second monday to friday a gray background.
The thirth a white bg again.
And the fourth weeks with monday to friday to have a gray background color.
What Im talking about is the background of the graph.
Is there a way to do this?
Chart.js clears the canvas before drawing (or redrawing) a chart.
We can jump in on this and draw our background once the chart is cleared. Just extend the Line chart and override the clear function in the initialize override.
Preview
Script
Chart.types.Line.extend({
name: "LineAlt",
initialize: function(data){
Chart.types.Line.prototype.initialize.apply(this, arguments);
// keep a reference to the original clear
this.originalClear = this.clear;
this.clear = function () {
this.originalClear();
// 1 x scale unit
var unitX = this.datasets[0].points[1].x - this.datasets[0].points[0].x;
var yTop = this.scale.startPoint;
var yHeight = this.scale.endPoint - this.scale.startPoint;
// change your color here
this.chart.ctx.fillStyle = 'rgba(100,100,100,0.8)';
// we shift it by half a x scale unit to the left because the space between gridline is actually a shared space
this.chart.ctx.fillRect(this.datasets[0].points[5].x - 0.5 * unitX, yTop, unitX * 5, yHeight);
this.chart.ctx.fillRect(this.datasets[0].points[15].x - 0.5 * unitX, yTop, unitX * 5, yHeight);
}
}
});
Then just use LineAlt instead of Line
var myNewChart = new Chart(ctx).LineAlt(data);
Fiddle - http://jsfiddle.net/oe2606ww/
Some people here have requested something that works for later versions, here's my hacked together solution that works on ChartJS 2.7.2 (EDIT: Apr 2020: Also 2.9.3) and could probably be adapted. Chart.types.Line.extend used in the answer above, doesn't seem to be valid in v2.
I managed to figure this out with help from this thread to get the plugin code, and also found this thread useful for gathering co-ordinates of the data points.
With some work this fiddle should allow you to pass the label array keys as start/stop positions via the following code (where 0 and 1 are the keys):
var start = meta.data[0]._model.x;
var stop = meta.data[1]._model.x;
You could loop this, along with the ctx.fillRect function to draw multiple rectangles.
Here's the working fiddle: http://jsfiddle.net/oe2606ww/436/
I combined #potatopeelings's and #v25's solutions for a chart.js v2 solution. It utilizes the format of #potatopeelings's solution, allowing to use an alternate chart type (LineAlt), and the updated implementation from #v25's solution.
Chart.controllers.LineAlt = Chart.controllers.line.extend({
draw: function (ease) {
if (this.chart.config.options.chartArea && this.chart.config.options.chartArea.backgroundColor) {
var ctx = this.chart.chart.ctx;
var chartArea = this.chart.chartArea;
var meta = this.chart.getDatasetMeta(0);
var start = meta.data[1]._model.x;
var stop = meta.data[2]._model.x;
ctx.save();
ctx.fillStyle = this.chart.config.options.chartArea.backgroundColor;
ctx.fillRect(start, chartArea.top, stop - start, chartArea.bottom - chartArea.top);
ctx.restore();
}
// Perform regular chart draw
Chart.controllers.line.prototype.draw.call(this, ease);
}
});
Then you can use the custom chart type just as in #potatopeelings's solution:
var myNewChart = new Chart(ctx, {type: 'LineAlt', data: data});
I'd try a little work around,I'd draw an image with four line each one with width 1px and a different color; then in a CSS sheet define:
canvas {
background-image: url(backgroundimage.jpg);
background-size: contain;
}

Plotting with HTML5 Canvas

I decided to day to embark on element and I can say so far it have been nightmare to get it work. All I want is to plot a sine graph. So after good reading I still cannot either get origins nor get it plot. Below is what I have tried (my first time ever with that tag so excuse my ignorance). What makes me wonder is the guy here have it but the codes are hard to understand for beginner like me.
HTML
<!DOCTYPE html>
<html>
<head>
<title>Graphing</title>
<link type="text/css" rel="Stylesheet" href="graph.css" />
<script type="text/JavaScript" src="graph.js" ></script>
</head>
<body>
<canvas id="surface">Canvas not Supported</canvas>
</body>
</html>
CSS
#surface
{
width:300;
height:225;
border: dotted #FF0000 1px;
}
JavScript
window.onload = function()
{
var canvas = document.getElementById("surface");
var context = canvas.getContext("2d");
arr = [0,15, 30,45,60, 90,105, 120, 135, 150, 165, 180 ];
var x=0;
var y = 0;
for(i=0; i<arr.length; i++)
{
angle = arr[i]*(Math.PI/180); //radians
sine = Math.sin(angle);
context.moveTo(x,y);
context.lineTo(angle,sine);
context.stroke();
//set current varibles for next move
x = angle;
y = sine;
}
}
Since the range of sin x is [-1,1], it will only return numbers between -1 and 1, and that means all you will be drawing is a dot on the screen.
Also I see that you have an array ranging from 0 to 180. I believe you are trying to draw the curve with x from 0 degree to 180 degree? You don't really need to do this (anyway 12 points are not enough to draw a smooth line). Just do it with a for loop, with lines being the number of fragments.
First we start off by moving the point to the left of the canvas:
context.moveTo(0, 100 /*somewhere in the middle*/); //initial point
In most cases the first point won't be in the middle. But for sine it is. (You might want to fix it later though.)
for (var i = 0; i < lines; i++) {
//draw line
}
That's the loop drawing the curve. But what should we put inside? Well you can just take the number returned by the sine function and scale it up, flip it upside down, and shift it down half the way. I do that because the coordinate system in JavaScript is 0,0 in the top left instead of in the bottom left.
var sine = Math.sin(i/scale*2)*scale;
context.lineTo(i*frag, -sine+scale);
//i * frag = the position of x scaled up
//-sine + scale = the position of y, flipped, scaled, shifted down
//i/scale*2 = random scale I put in... you might want to figure out the
// correct scale with some math
So that's it. Viola, you have successfully plotted a graph in JavaScript.
Oh yes, don't forget to actually tell it to draw it on the canvas after the for loop has done its job:
context.stroke();
The demo: http://jsfiddle.net/DerekL/hK5rC/
PS: I see that you are trying to resize the canvas using CSS. Trust me, it won't work. :) You will have to define the dimension in HTML.

geographic chart by nation

I need to implement a chart like geographic chart which is an image of America seperated by state by state. And then, based on data for each state, it will the chart will display state by color.
For example we have
California : 20 products
Texas: 100 products
Ohio: 5 products
.....
If the number of product for a state > 20, then display that state with GREEN color, or else, display it with RED color
Until now I have no ideas how to do it.
I intend to split the America Map into 50 divs and color it, but it is not effective.
There are some geo chart frameworks, for example Google Geo Chart, though it is not fully customizeable.
But you can do it by using the jVectorMap framework. Download jVectorMap 1.2.2, also choose some map of the USA (I used the Mercator and you can use the following code:
<head>
<link rel="stylesheet" href="jquery-jvectormap-1.2.2.css" type="text/css" />
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.0.min.js"></script>
<script type="text/javascript" src="jquery-jvectormap-1.2.2.min.js"></script>
<script type="text/javascript" src="http://jvectormap.com/js/jquery-jvectormap-us-merc-en.js"></script>
<script type="text/javascript">
$(function(){
var data = { "US-CA": 20, "US-TX": 100, "US-OH": 5 };
var colors = {};
// create an object with colors
for (var key in data) {
var value = data[key];
colors[value] = value > 20 ? "#00FF00" : "#FF0000";
}
$('#map_canvas').vectorMap({
map: 'us_merc_en',
series: {
regions: [{
values: data,
scale: colors
}]
}
});
});
</script>
</head>
<body>
<div id="map_canvas" style="width: 400px; height: 300px;"></div>
</body>
The color assigning part in the for loop is quite tricky because of some limitations of the framework. Also it requires special naming for states like US-CA. But in result you will see green Texas and red California with Ohio.
Also the framework is open source and if you need some more complex functionality, you can update the code yourself.

Categories

Resources