<html lang="en">
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body onload="init()">
<canvas id="canvas" width="400" height="400" style="border:solid 2px black"></canvas>
<ul id="sliders"></ul>
</body>
</html>
var canvas;
var context;
// Size of the histogram
var width = 150, height=150;
// The origin, bottom left corner, relative to the origin in the canvas
var x = 40, y = 190;
// Data to be visualized
var values = [1, 10, 2, 7, 9, 2, 34, 100, 12, 14, 19];
//init function is launch when the page is loaded.
function init() {
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
var list = document.getElementById('sliders');
// Create the sliders for changing the values.
var max = getMax(values);
for (i=0; i < values.length; i++) {
var input = document.createElement('input');
var li = document.createElement('li');
var label = document.createElement('label');
label.setAttribute('for', 'id'+i);
label.textContent = 'value' + i + ' ';
li.appendChild(label);
input.setAttribute('type', 'range');
input.setAttribute('id', 'id' + i);
// Set their value and max attributes correctly
input.setAttribute('max', max);
input.value = values[i];
// Add an onchange event listener and pass the
// index of the slider to the callback
input.setAttribute('oninput', 'changeValue(' + i + ')');
li.appendChild(input);
list.appendChild(li);
}
makeHistogram(x, y,
width, height,
values);
// center of pie x and y, radius, values
makePieChart(300, 100, 90, values);
// Draw broken lines chart
makeBrokenLines(40, 370, width, height, values);
}
// callback for sliders' onchange events.
function changeValue(index) {
var value = document.getElementById("id"+index).value;
// put the slider value in the values array
values[parseInt(index)] = parseInt(value);
// clear the canvas
context.clearRect(0,0, canvas.width, canvas.height);
// redraw the charts
makeHistogram(x, y, width, height, values);
makePieChart(300, 100, 90, values);
makeBrokenLines(40, 370, width, height, values);
}
// returns the max from the elements of the values array.
function getMax(values) {
var maxValue = 0;
for (i=0; i<values.length; i++) {
if (maxValue < values[i])
maxValue = values[i];
}
return maxValue;
}
function drawAxis(width, height, values, maxValue) {
// remember: we have the origin of the coordinate system at bottom left
// Y values above will be negative
context.strokeStyle = "black"; //We draw in black the outline.
context.fillStyle = "black"; //We fill in black.
//We define the vertical step unit. Is it 10 ? 20 ? 100 ? 1000 ? Depending on the
// max unit value, we decide how the steps will be for the ticks
var unit = 1;
while (maxValue / (unit*10) > 1) {
unit *= 10;
}
//We define the highest vertical step.
var yMaxOnAxis = parseInt(maxValue) / unit;
// Everything is in a path, all drawing orders will be drawn by a final call
// to context.stroke() at the end of the function.
context.beginPath(); //Begin a new path.
// Draw the axis' lines
context.moveTo(0, 0); //We place the cursor to origin.
context.lineTo(0, -height); //We draw the vertical line.
context.moveTo(0, 0); //We place the cursor to origin.
context.lineTo(width, 0); //We draw the horizontal line.
// ticks/labels on the vertical line
context.textAlign = "left";
for (i=0; i <= yMaxOnAxis; i++) {
// move to the next graduation. the y value is negative due to
// the change of the origin by a call to translate(x,y) in the drawHistogram
// function.
context.moveTo(0, -height / yMaxOnAxis * i );
// draw an horizontal line, 5 pixels long, on the left of the axis
context.lineTo(-5, -height / yMaxOnAxis * i );
// write the tick value, 25 pixels on the left of the axis
context.fillText(i*unit, -25, -height / yMaxOnAxis * i );
}
// Ticks/labels on the horizontal line
var counter = 0;
// text centered below the tick
context.textAlign = "center";
// graduation on the horizontal line.
var rectanglesWidth = width / values.length;
for (i=0; i <= values.length; i++) {
// Move to the next horizontal position of the tick
context.moveTo(i*rectanglesWidth , 0);
// draw a vertical line 5 pixels long: the tick
context.lineTo(i*rectanglesWidth , 5);
// write tick label 15 pixels below the tick
context.fillText(i, i*rectanglesWidth , 15);
counter++;
}
// Draw everything in the path
context.stroke();
}
// MakeHistogram building a bar plot. x, y is the bottom left position of the
// histogram. Easier to reason with this coordonate system
function makeHistogram(x, y, width, height, values) {
context.save();
// Change the origin at bottom left. If we draw "above", Y values will be negative.
// y=0 is the horizontal line at bottom
context.translate(x, y);
// Compute the max of the values array
var maxValue = getMax(values);
// step in pixels between two horizontal values for bar plot.
var rectWidth = width / parseFloat(values.length);
// step in pixels between two vertical values for bar plot.
var vStep = -height / parseFloat(maxValue);
//Set fill color to red and stroke color to black.
context.fillStyle = "red";
context.strokeStyle = "black";
// Draw the histogram rectangles
for(i=0; i < values.length; i++) {
//We draw a filled red rectangle to represent the current value.
context.fillRect(i * rectWidth, 0,
rectWidth, vStep * values[i]);
//We draw the outline of rectangle.
context.strokeRect(i * rectWidth, 0,
rectWidth, vStep * values[i]);
}
// draw the axis
drawAxis(width, height, values, maxValue);
context.restore();
}
//makePieChart draw a circle graph with values table.
function makePieChart(cx, cy, radius, values) {
context.save();
// Compute the sum of all values
var sum=0;
for(var n=0; n < values.length; n++) {
sum += values[n];
}
//Initialization of red green blue colors.
var red = 0;
var green = 0;
var blue = 0;
//starting and ending angles of each pie section
var startingAngle = 0;
var endAngle = 0;
//The percentage the current value represents, compare to the total,
// we are in a closed circle, the sum is 100%
var percentage;
//We draw in grey the outline of the section.
context.strokeStyle = "grey";
// Draw the pie chart, clockwise, à la HTML5
//for (var i=values.length-1; i> 0; i--) { // for ccw display
for(var i = 0; i < values.length; i++) {
context.beginPath(); //Begin a new path.
// We change the colors depending on the i-value. Just a trick based
// on the modulo. Will produce different colors for the pie sections
switch (i%3) {
case 0: //If i modulo 3 equals 0:
red += 80; //We add red.
break;
case 1: //If i modulo 3 equals 1:
green += 80; //We add green.
break;
case 2: //If i modulo 3 equals 2:
blue += 80; //We add blue.
break;
default: //If there is an error.
alert("we have encountered an error");
return ; //and we stop makePieChart.
}
context.fillStyle = "rgb(" + red + "," + green + "," + blue +")";
// percentage of the circle for current section, will give the angles
percentage = values[i] / parseFloat(sum);
endAngle = startingAngle + Math.PI*2*percentage;
// draw an arc between starting angle and end angle.
context.arc(cx, cy, radius, startingAngle, endAngle);
// draw a line between end angle and center of circle.
context.lineTo(cx, cy);
//The next starting angle is the current end angle.
startingAngle = endAngle;
context.fill(); // draw pie section
context.stroke(); // draw the outline.
context.closePath(); // Close the path.
context.restore();
}
}
// draw a broken line chart
function makeBrokenLines(x, y, width, height, values) {
context.save();
// Move origin of the coordinate system at x, y, bottom left corner
context.translate(x, y);
var maxValue = getMax(values);
// distance between two horizontal values, in pixels
var hStep = width / parseFloat(values.length);
// step between two vertical values, in pixels
var vStep = -height / parseFloat(maxValue);
// set fill color to black, for drawing the circle plots
context.fillStyle = "black";
// thickness of the lines
context. lineWidth = 1;
// set the cursor to origin.
context.moveTo(0 , 0);
// All lines are drawn into a path
context.beginPath();
for(i=0; i<values.length; i++) {
context.lineTo(i * hStep, vStep * values[i]);
}
context.stroke(); // draw the path with all the lines
// Draw the filled black circles at each value's coordinate
for(i=0; i<values.length; i++) {
context.beginPath();
context.arc(i * hStep, vStep * values[i], 3, 0, 2*Math.PI);
context.fill(); //We fill all circles.
}
// draw the X and Y axis
drawAxis(width, height, values, maxValue);
context.restore();
}
Output
300px
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |