Skip to content

Instantly share code, notes, and snippets.

@meylingtaing
Last active September 21, 2022 16:34
Show Gist options
  • Save meylingtaing/5cdd8d0fe72674a71f94f813c4362969 to your computer and use it in GitHub Desktop.
Save meylingtaing/5cdd8d0fe72674a71f94f813c4362969 to your computer and use it in GitHub Desktop.
my ascii art colorizer
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="main.css">
<link rel="stylesheet" href="colors.css">
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Oxygen+Mono">
<title>Ascii Art Colorizer</title>
</head>
<body>
<div id="page-content">
<style id="page-style">
#ascii-art-grid {
font-size: 1.5em;
font-family: 'Oxygen Mono', monospace;
line-height: normal;
/* Disable highlight. Stackoverflow told me how to do this. */
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select:none;
user-select:none;
-o-user-select:none;
}
#ascii-art-grid-div {
margin-right: 2em;
}
.char-color {
outline: 1px solid #444;
}
.char-color.selected {
outline: 1px solid #FFF;
}
.char-color:hover {
cursor: pointer;
}
#generated-html {
overflow-y: scroll;
}
</style>
<!-- This is for the new color that we add. It gets populated via javascript -->
<style id="extra-style"></style>
<div style="text-align:center">
<h1>
<a href="/">projects</a> | <a href="/blog">blog</a>
</h1>
<p>
<hr>
</p>
</div>
<div style="text-align:center">
<a href="/ascii/original">[original]</a>
<a href="/ascii/fanart">[fan&nbsp;art]</a>
<b>color-izer</b>
<a href="/ascii/howto">[how&nbsp;I&nbsp;display&nbsp;ascii&nbsp;art]</a>
</div><br>
The code for this is now in a <a href="https://gist.github.com/meylingtaing/5cdd8d0fe72674a71f94f813c4362969">gist</a>!
<br><br>
<span class="new-color-color">Add new color:</span>
<input type="text" placeholder="class name" id="color-class-name-input" />
<input type="text" placeholder="css color" id="color-value-input" />
<input type="button" value="+" id="add-color-link" />
<br><br>
<div id="color-links">
<a href="#" class="white change-color-link" data-color="white">white</a>
<a href="#" class="gray change-color-link" data-color="gray">gray</a>
<a href="#" class="lightgray change-color-link" data-color="lightgray">lightgray</a>
<a href="#" class="yellow change-color-link" data-color="yellow">yellow</a>
<a href="#" class="floyellow change-color-link" data-color="floyellow">floyellow</a>
<a href="#" class="yellorange change-color-link" data-color="yellorange">yellorange</a>
<a href="#" class="orange change-color-link" data-color="orange">orange</a>
<a href="#" class="gold change-color-link" data-color="gold">gold</a>
<a href="#" class="lightgold change-color-link" data-color="lightgold">lightgold</a>
<a href="#" class="pink change-color-link" data-color="pink">pink</a>
<a href="#" class="darkpink change-color-link" data-color="darkpink">darkpink</a>
<a href="#" class="redpink change-color-link" data-color="redpink">redpink</a>
<a href="#" class="orangepink change-color-link" data-color="orangepink">orangepink</a>
<a href="#" class="lightblue change-color-link" data-color="lightblue">lightblue</a>
<a href="#" class="lightblue2 change-color-link" data-color="lightblue2">lightblue2</a>
<a href="#" class="lightblue3 change-color-link" data-color="lightblue3">lightblue3</a>
<a href="#" class="mediumblue change-color-link" data-color="mediumblue">mediumblue</a>
<a href="#" class="darkblue change-color-link" data-color="darkblue">darkblue</a>
<a href="#" class="indigo change-color-link" data-color="indigo">indigo</a>
<a href="#" class="indigo2 change-color-link" data-color="indigo2">indigo2</a>
<a href="#" class="violet change-color-link" data-color="violet">violet</a>
<a href="#" class="purple change-color-link" data-color="purple">purple</a>
<a href="#" class="blue change-color-link" data-color="blue">blue</a>
<a href="#" class="red change-color-link" data-color="red">red</a>
<a href="#" class="red2 change-color-link" data-color="red2">red2</a>
<a href="#" class="darkred change-color-link" data-color="darkred">darkred</a>
<a href="#" class="tan change-color-link" data-color="tan">tan</a>
<a href="#" class="lighttan change-color-link" data-color="lighttan">lighttan</a>
<a href="#" class="brown change-color-link" data-color="brown">brown</a>
<a href="#" class="darkbrown change-color-link" data-color="darkbrown">darkbrown</a>
<a href="#" class="choco change-color-link" data-color="choco">choco</a>
<a href="#" class="darkchoco change-color-link" data-color="darkchoco">darkchoco</a>
<a href="#" class="green change-color-link" data-color="green">green</a>
<a href="#" class="darkgreen change-color-link" data-color="darkgreen">darkgreen</a>
<a href="#" class="darkergreen change-color-link" data-color="darkergreen">darkergreen</a>
<a href="#" class="limegreen change-color-link" data-color="limegreen">limegreen</a>
<a href="#" class="yellowgreen change-color-link" data-color="yellowgreen">yellowgreen</a>
<a href="#" class="black change-color-link" data-color="black">black</a>
<a href="#" class="ascii-art-caption change-color-link" data-color="ascii-art-caption">ascii&#8209;art&#8209;caption</a>
</div>
<br>
<button id="clear-selected">Clear Selected</button>
<div id="ascii-art-grid-div">
<pre id="ascii-art-grid"></pre>
</div>
<div id="error-message" class="red"></div>
<textarea id="ascii-art-input" cols="80" rows="10">
Paste ascii art here...</textarea>
<br>
<button id="submit-ascii-art">Start Color-izing</button>
<button id="generate-html">Generate HTML/CSS</button>
<br><br>
<textarea id="generated-html" cols="46" rows="10">
Generated HTML will go here</textarea>
<textarea id="generated-css" cols="30" rows="10">
Generated CSS will go here</textarea>
<br>
<button id="parse-html">Parse HTML</button>
<script>
const default_color = 'gray';
// The colors are stored in a 2d array. Each element of the array is a
// class name that represents a certain color in the colors css file
var color_arr = [];
// Number of lines in the ascii art
var rows;
// Set to 'selecting' when we are selecting (highlighting, mousedown) // characters in the ascii art grid
var selecting = "";
// Keep track of all the css color values so we can more easily generate
// them later
var css_color_values = {};
css_color_values["white"] = "#FFF";
css_color_values["gray"] = "#999";
css_color_values["lightgray"] = "#CCC";
css_color_values["yellow"] = "yellow";
css_color_values["floyellow"] = "#fdf001";
css_color_values["yellorange"] = "#FD0";
css_color_values["orange"] = "orange";
css_color_values["gold"] = "#FF6";
css_color_values["lightgold"] = "#FF8";
css_color_values["pink"] = "lightpink";
css_color_values["darkpink"] = "#E89";
css_color_values["redpink"] = "#F86";
css_color_values["orangepink"] = "#FB7";
css_color_values["lightblue"] = "lightblue";
css_color_values["lightblue2"] = "#8CF";
css_color_values["lightblue3"] = "#8AF";
css_color_values["mediumblue"] = "#78F";
css_color_values["darkblue"] = "#545092";
css_color_values["indigo"] = "#97F";
css_color_values["indigo2"] = "#A7C";
css_color_values["violet"] = "#E5F";
css_color_values["purple"] = "#C3C";
css_color_values["blue"] = "#37E";
css_color_values["red"] = "red";
css_color_values["red2"] = "#E34";
css_color_values["darkred"] = "#C33";
css_color_values["tan"] = "#FC8";
css_color_values["lighttan"] = "#FD9";
css_color_values["brown"] = "#D50";
css_color_values["darkbrown"] = "#A30";
css_color_values["choco"] = "#B85";
css_color_values["darkchoco"] = "#963";
css_color_values["green"] = "#3D5";
css_color_values["darkgreen"] = "#3A5";
css_color_values["darkergreen"] = "#171";
css_color_values["limegreen"] = "#0F0";
css_color_values["yellowgreen"] = "#CF7";
css_color_values["black"] = "#000";
function get_ascii_art_input() {
// Get the input string
var ascii_art = document.getElementById("ascii-art-input").value;
rows = ascii_art.split(/\n/);
// Get the size of the input
var num_rows = rows.length;
var num_cols = Math.max(...rows.map(x => x.length));
// Create the colors array -- keep any colors we already modified
for (let i = 0; i < num_rows; i++) {
let new_color_arr = [];
for (let j = 0; j < rows[i].length; j++) {
if (typeof color_arr[i] != 'undefined' &&
typeof color_arr[i][j] != 'undefined')
{
new_color_arr[j] = color_arr[i][j];
}
else {
new_color_arr[j] = default_color;
}
}
color_arr[i] = new_color_arr;
}
// Display it
display_grid();
}
document.addEventListener('mouseup', stop_selecting);
function display_grid() {
var grid_html = '';
rows.forEach(function (row, index) {
for (let i = 0; i < row.length; i++) {
let color = color_arr[index][i];
grid_html = grid_html.concat(
'<span class="', color, ' char-color"',
'data-col="', i, '"',
' data-row="', index, '" data-color="', color, '">',
row.charAt(i),
'</span>'
);
}
grid_html = grid_html.concat("\n");
});
document.getElementById("ascii-art-grid").innerHTML = grid_html;
var char_elts = document.getElementsByClassName("char-color");
for (let i = 0; i < char_elts.length; i++) {
char_elts[i].addEventListener('mousedown', start_selecting);
char_elts[i].addEventListener('mousemove', continue_selecting);
}
}
function start_selecting(e) {
var classes = this.className;
if (classes.match(/selected/)) {
selecting = "deselecting";
this.classList.remove("selected");
}
else {
selecting = "selecting";
this.classList.add("selected");
}
}
function continue_selecting(e) {
if (selecting == "selecting") {
this.classList.add("selected");
}
else if (selecting == "deselecting"){
this.classList.remove("selected");
}
}
function stop_selecting(e) {
selecting = "";
}
function clear_selected() {
var selected_elts = document.getElementsByClassName('selected');
while (selected_elts.length > 0) {
selected_elts[0].classList.remove('selected');
}
}
function change_char_color(e) {
// What color was selected?
var color_class = this.getAttribute('data-color');
// Get all selected elements and change their color
var selected_elts = document.getElementsByClassName('selected');
for (let i = 0; i < selected_elts.length; i++) {
let old_color = selected_elts[i].getAttribute('data-color');
selected_elts[i].setAttribute('data-color', color_class);
selected_elts[i].classList.remove(old_color);
selected_elts[i].classList.add(color_class);
let row = selected_elts[i].getAttribute('data-row');
let col = selected_elts[i].getAttribute('data-col');
color_arr[row][col] = color_class;
}
return false;
}
function generate_html() {
// We run into issues if the first span consists of only spaces, so
// let's figure out the first color that's actually used and change
// the first set of spaces to that color
var first_char_color = default_color;
get_first_char_color:
for (let i = 0; i < color_arr.length; i++) {
for (let j = 0; j < color_arr[i].length; j++) {
let char = rows[i].charAt(j);
if (char != ' ') {
first_char_color = color_arr[i][j];
break get_first_char_color;
}
}
}
// Go through the ascii art grid
var curr_color = first_char_color;
var html = '<span class="' + curr_color + '">';
var colors_used = {};
colors_used[curr_color] = 1;
var css = `.${curr_color} { color: ${css_color_values[curr_color]} }\n`;
for (let i = 0; i < color_arr.length; i++) {
for (let j = 0; j < color_arr[i].length; j++) {
// Check if the color has changed
let char = rows[i].charAt(j);
if ((char != ' ') && (color_arr[i][j] != curr_color)) {
curr_color = color_arr[i][j];
html = html.concat(
'</span>', '<span class="', curr_color, '">');
// Add it to the css if it's not there yet
if (colors_used[curr_color] != 1) {
css = css.concat(`.${curr_color} { color: ${css_color_values[curr_color]} }\n`);
colors_used[curr_color] = 1;
}
}
// Add the next letter
html = html.concat(rows[i].charAt(j));
}
html = html.concat("\n");
}
html = html.concat("</span>");
document.getElementById('generated-html').value = html;
document.getElementById('generated-css').value = css;
}
function parse_html() {
display_error('');
// Get the html input
var html = document.getElementById('generated-html').value;
var pre_elt = document.createElement('pre');
// Error check?!
pre_elt.innerHTML = html;
// Walk through each span and fill out the color_arr
var nodes = pre_elt.childNodes;
var new_color_arr = [];
var i = 0;
var j = 0;
new_color_arr[0] = [];
for (node of nodes) {
let color;
if (node.nodeType != Node.ELEMENT_NODE || node.tagName != 'SPAN') {
display_error('Invalid input - not all nodes are <span>');
}
else {
// Make sure it's just plain text inside the span
if (node.childNodes.length != 1) {
display_error(
'Invalid input - <span> has multiple nodes',
);
console.log(node.childNodes[1].nodeType);
console.log(node.childNodes[1]);
}
else if (node.childNodes[0].nodeType != Node.TEXT_NODE) {
display_error(
'Invalid input - <span> has something other than text',
);
console.log(node.childNodes[0].nodeType);
console.log(node.childNodes[0]);
}
color = node.getAttribute('class');
let text = node.textContent;
for (let n = 0; n < text.length; n++) {
if (text.charAt(n) == '\n') {
i++;
j=0;
new_color_arr[i] = [];
}
else {
new_color_arr[i][j] = color;
j++;
}
}
}
}
color_arr = new_color_arr;
rows = pre_elt.textContent.split(/\n/);
display_grid();
}
function change_new_color_color (e) {
if (e.keyCode === 13) { // Enter
var value = document.getElementById("color-value-input").value;
var style = document.getElementById("extra-style");
style.innerHTML = `.new-color-color { color: ${value} }`;
}
}
function add_color_link() {
// TODO: Actually check and see if we were given valid inputs?
var name = document.getElementById("color-class-name-input").value;
var value = document.getElementById("color-value-input").value;
// First, add the css to this page
var style = document.getElementById("page-style");
style.append(`.${name} { color: ${value} }\n`);
css_color_values[name] = value;
// And then add a link for it
var color_links_div = document.getElementById("color-links");
var new_link = document.createElement('a');
new_link.setAttribute('href', '#');
new_link.setAttribute('class', name + " change-color-link");
new_link.setAttribute('data-color', name);
new_link.innerHTML = name;
color_links_div.append(new_link);
color_links_div.append("\n");
new_link.onclick = change_char_color;
// Clear out all the inputs (and the color preview)
document.getElementById("color-class-name-input").value = '';
document.getElementById("color-value-input").value = '';
document.getElementById("extra-style").innerHTML = '';
}
function display_error(err) {
document.getElementById('error-message').textContent = err;
}
document.getElementById("submit-ascii-art").onclick = get_ascii_art_input;
document.getElementById("generate-html").onclick = generate_html;
document.getElementById("clear-selected").onclick = clear_selected;
document.getElementById("parse-html").onclick = parse_html;
document.getElementById("add-color-link").onclick = add_color_link;
document.getElementById("color-value-input").onkeyup = change_new_color_color;
var color_links = document.getElementsByClassName("change-color-link");
for (let i = 0; i < color_links.length; i++)
color_links[i].onclick = change_char_color;
</script>
</div>
</body>
</html>
.white { color: #FFF }
.gray { color: #999 }
.lightgray { color: #CCC }
.yellow { color: yellow }
.floyellow { color: #fdf001 }
.yellorange { color: #FD0 }
.orange { color: orange }
.gold { color: #FF6 }
.lightgold { color: #FF8 }
.pink { color: lightpink }
.darkpink { color: #E89 }
.redpink { color: #F86 }
.orangepink { color: #FB7 }
.lightblue { color: lightblue }
.lightblue2 { color: #8CF }
.lightblue3 { color: #8AF }
.mediumblue { color: #78F }
.darkblue { color: #545092 }
.indigo { color: #97F }
.indigo2 { color: #A7C }
.violet { color: #E5F }
.purple { color: #C3C }
.blue { color: #37E }
.red { color: red }
.red2 { color: #E34 }
.darkred { color: #C33 }
.tan { color: #FC8 }
.lighttan { color: #FD9 }
.brown { color: #D50 }
.darkbrown { color: #A30 }
.choco { color: #B85 }
.darkchoco { color: #963 }
.green { color: #3D5 }
.darkgreen { color: #3A5 }
.darkergreen { color: #171 }
.limegreen { color: #0F0 }
.yellowgreen { color: #CF7 }
.black { color: #000 }
body {
background-color: #333;
color: #CCC;
font-family: 'Oxygen Mono', monospace;
width: 90%;
margin: auto;
line-height: 1.5;
}
a {
color: #8DF;
text-decoration: underline;
}
a.footnote {
vertical-align: super;
font-size: smaller;
text-decoration: none;
color: #FF6;
}
a.reversefootnote {
text-decoration: none;
}
.continue-reading-link {
text-align: right;
}
/* Blog stuff */
h2, h2 > a {
color: #EEE;
}
h3 {
color: #DDD;
}
h4 {
color: #999;
font-weight: normal;
}
hr {
border: 0;
border-top: 3px dashed #37E;
}
blockquote, blockquote strong {
color: #B9F;
}
table, tr, td, th {
border: 1px solid #999;
border-collapse: collapse;
padding: 3px;
}
table {
margin-bottom: 1em;
margin-left: auto;
margin-right: auto;
text-align: center;
}
strong {
color: #EEE;
}
p code {
color: #333;
background-color: #CCC;
font-weight: bold;
padding: .25em;
}
div.code {
color: #000;
background-color: #CCC;
padding: .25em;
padding-left: 1em;
overflow: scroll;
}
textarea {
background-color: #CCC;
font: monospace;
}
.tags a {
color: #999;
font-size: .75em;
}
@media (min-width: 55em) {
body {
width: 50em;
}
}
@media (max-width: 35em) {
.ascii-art {
font-size: .8em;
}
}
img {
max-width: 100%;
/* max-height: 90vh */;
margin: auto;
display: block;
}
#page-content { margin-top: 1em }
.ascii-art {
font-weight: bold;
line-height: 1.35;
}
.ascii-art i, .ascii-art-caption {
font-weight: normal;
color: #999;
font-style: italic;
}
.underline { text-decoration: underline }
.bold { font-weight: bold }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment