<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3fc/5.0.0/d3fc.bundle.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/d3fc/5.0.0/d3fc.min.css" rel="stylesheet"/>
</head>
<body>
<pre id='ascii-output'>
</pre>
<div id='ascii-dom'>
</div>
</body>
</html>
pre {
font-size: 8px;
}
svg text {
font-size: 2px;
}
svg {
overflow: hidden !important;
}
#ascii-dom svg {
width: 0;
height: 0;
overflow: hidden;
}
(function() {
function AsciiCanvas(width, height) {
var buffer = Array.apply(null, Array(width * height)).map(String.prototype.valueOf, ' ');
var self = this;
this.render = function() {
var stringBuffer = '';
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
stringBuffer += buffer[x + y * width];
}
stringBuffer += '\n';
}
return stringBuffer;
};
this.setPixel = function(x, y, char) {
x = Math.floor(x);
y = Math.floor(y);
if (x < 0 || x > width - 1 ||
y < 0 || y > height - 1) {
return;
}
buffer[x + y * width] = char;
};
this.renderSvg = function(svg) {
var paths = svg.selectAll('.bar path');
paths.each(function() {
var rect = new Rectangle(this);
rect.render(self);
});
var labels = svg.selectAll('text');
labels.each(function() {
var label = new Text(this);
label.render(self);
});
};
}
// obtains the boudns of an SVG element
function getBounds(svgElement) {
var bbox = svgElement.getBBox();
var transform = svgElement.getCTM();
return {
left: bbox.x + transform.e,
right: bbox.x + bbox.width + transform.e,
top: bbox.y + transform.f,
bottom: bbox.y + bbox.height + transform.f
};
}
// a text primtive that can be rendered to an AsciiCanvas
function Text(svgText) {
var bounds = getBounds(svgText);
var text = svgText.textContent;
this.render = function(asciiCanvas) {
var x = bounds.left + ((bounds.right - bounds.left) / 2) - (text.length / 2),
y = bounds.top;
for (var i = 0; i < text.length; i++) {
asciiCanvas.setPixel(x, y, text[i]);
x++;
}
};
}
// a rectangle primtive that can be rendered to an AsciiCanvas
function Rectangle(svgRect) {
var bounds = getBounds(svgRect);
var fill = svgRect.getAttribute('ascii-fill') || '#';
this.render = function(asciiCanvas) {
for (var i = bounds.left; i < bounds.right - 1; i++) {
for (var j = bounds.top; j < bounds.bottom - 1; j++) {
asciiCanvas.setPixel(i, j, fill);
}
}
};
}
// generate some random data
var data = d3.range(10).map(Math.random);
var colors = '£$%@£^&!';
var width = 60, height = 20;
d3.select('#ascii-dom').style({
width: width + 'px',
height: height + 'px'
});
// render a bar series via the cartesian chart component
var barSeries = fc.series.bar()
.key(fc.util.fn.identity)
.xValue(fc.util.fn.index)
.yValue(fc.util.fn.identity)
.decorate(function(sel) {
sel.enter().select('path')
.attr('ascii-fill', function(d, i) {
return colors[i % colors.length];
});
});
var chart = fc.chart.cartesian(
d3.scale.linear(),
d3.scale.linear())
.xDomain([-1, data.length])
.yDomain([0, 1])
.margin(0)
.xTickPadding(1)
.xTickSize(0)
.plotArea(barSeries);
var index = 0;
function render() {
if (index === data.length) {
index = 0;
data = d3.range(10).map(Math.random);
}
// perform a single iteration of the bubble sort
var temp;
for (var j = index; j > 0; j--) {
if (data[j] < data[j - 1]) {
temp = data[j];
data[j] = data[j - 1];
data[j - 1] = temp;
}
}
index++;
// re-render the chart
d3.select('#ascii-dom')
.datum(data)
.transition()
.duration(500)
.call(chart);
}
setInterval(render, 1000);
render();
function svgToAscii() {
var canvas = new AsciiCanvas(width, height);
canvas.renderSvg(d3.select('#ascii-dom'));
var ascii = canvas.render();
d3.select('#ascii-output').text(ascii);
requestAnimationFrame(svgToAscii);
}
svgToAscii();
})();
Output
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. |