character loops
by Laurens Maneschijn
HTML
<hr>
Test character loops for e.g. text only loading animation.
<hr>
<details><summary>Edit characters: ...</summary>
One loop on each line:
<textarea id="source">
1234
❶❷❸❹
➀➁➂➃
⓵⓶⓷⓸
Hello world.
bdqp
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
⠓⠋⠙⠚
⠦⠖⠲⠴
⠶⠧⠏⠛⠹⠼
⣶⣧⣏⡟⠿⢻⣹⣼
⠉⠛⠿⣿⣶⣤⣀
|/-\|/-\
˄˃˅˂
▲▶▼◀
⮫⮯⮨⮬
⏫⏩⏬⏪
↑↗→↘↓↙←↖
↗↘↙↖
⇑⇗⇒⇘⇓⇙⇐⇖
⇗⇘⇙⇖
⬆⬈➡⬊⬇⬋⬅⬉
⬈⬊⬋⬉
▝▗▖▘
▙▛▜▟
◳◲◱◰
◷◶◵◴
◓◑◒◐
◝◞◟◜
⏳⌛
⧗⧖
⊕⊗
⨁⨂
🞊🞉🞈🞇🞆🞅
🞉🞈🞇🞆🞅
🞉🞈🞇🞆🞅🞆🞇🞈
🞉🞈🞇🞆🞅🞅🞆🞇🞈🞉
🞅🞆🞇🞈🞉◉⚬🞄·
🂡🂢🂣🂤🂥🂦🂧🂨🂩🂪🂫🂬🂭🂮
🂱🂲🂳🂴🂵🂶🂷🂸🂹🂺🂻🂼🂽🂾
🃁🃂🃃🃄🃅🃆🃇🃈🃉🃊🃋🃌🃍🃎
🃑🃒🃓🃔🃕🃖🃗🃘🃙🃚🃛🃜🃝🃞
🕛🕐🕑🕒🕓🕔🕕🕖🕗🕘🕙🕚
🌑🌒🌓🌔🌕🌖🌗🌘
⌜⌝⌟⌞
{"parts":["⌜ "," ⌝"," ⌟","⌞ "],"style":{"font-family":"monospace","white-space":"pre"}}
{"parts":["⌜ \n "," ⌝\n "," \n ⌟"," \n⌞ "],"style":{"font-family":"monospace","white-space":"pre","line-height":"1"}}
{"parts":[" ⬆ \n \n "," ⬈\n \n "," \n ➡\n "," \n \n ⬊"," \n \n ⬇ "," \n \n⬋ "," \n⬅ \n ","⬉ \n \n "],"style":{"font-family":"monospace","white-space":"pre","line-height":"1"}}
</textarea>
</details>
<hr>
<button class="square" onclick="stop();" > ⏹ </button>
<button class="square" onclick="toggle();" > ⏯ </button>
<button class="square" onclick="tick();" > 1 </button>
<button class="square" onclick="restart();" > ▶ </button>
<input type="range"
min="0"
max="1000"
step="10"
value="100"
ondblclick="this.value=100; this.onchange();"
onchange="delay=this.value;this.title=this.value;"
onmouseover="this.title=this.value";
>
<input type="checkbox" onchange="reverse = this.checked;" >
<br>
font: <select id="fontfamily"></select>
<input type="range"
min="0"
max="40"
step="1"
ondblclick="this.value=20; this.onchange();"
onchange="document.querySelector('#target').style.fontSize=this.value+'px';this.title=this.value;"
onmouseover="this.title=this.value";
>
<hr>
<div id="target"></div>
<hr>
amp-what examples:
<a target="_blank" href="http://www.amp-what.com/unicode/search/braille%20pattern%20dots">⣿</a>
<a target="_blank"...
CSS
* {
box-sizing: border-box;
}
#target {
font-size: 20px;
font-family: monospace;
}
span.charset {
display: inline-block;
margin: 2px;
padding: 2px;
min-width: 1.7em;
min-height: 1.7em;
background: #8888;
border-radius: 0;
text-align: center;
vertical-align: middle;
line-height: 1.5;
}
textarea {
white-space: pre;
width: 100%;
height: 200px;
resize: vertical;
}
details > summary {
cursor: pointer;
user-select: none;
border: 2px outset #888;
background: #8882;
}
button.square {
vertical-align: middle;
line-height: 1.5;
aspect-ratio: 1/1;
}
input[type="range"] {
position: relative;
}
input[type="range"]::after {
content: attr(title);
position: absolute;
z-index: 9;
top: 15px;
}
JavaScript
var _target = document.querySelector('#target');
var _source = document.querySelector('#source');
var charsets = [];
var running = false;
var delay = 100;
var reverse = false;
init();
function init() {
console.clear();
_source.addEventListener('change', restart);
_source.addEventListener('keyup', restart);
restart();
init_fontfamily_select();
}
function readCharSets() {
_target.innerHTML = '';
charsets = [];
lines = _source.value || '';
lines.split('\n')
// .filter(s => s.trim() !== '')
.forEach((line) => {
if (line.trim() === '') {
// add a newline in display target:
target.appendChild(document.createElement('div'));
return;
}
var charset = {str: line};
// support complex lines as a json line
// e.g.: '{"parts":["1","2","3","4"],"style":{}}';
if (line[0] === '{') {
try {
var parsed = JSON.parse(line);
console.log(parsed, line);
charset.str = parsed.str;
charset.parts = parsed.parts;
charset.style = parsed.style;
} catch (e) {
console.log(e);
}
}
// if (containsSurrogatePair(line)) {
// console.log('containsSurrogatePair:', line);
// }
if (charset.str && !charset.parts) {
charset.parts = characterArrayFromString(charset.str);
}
// if (!charset.str && charset.parts) {
// charset.str = charset.parts.join('');
// }
if (!charset.element) {
var el = charset.element = document.createElement('span');
el.className = 'charset';
if (charset.style) {
Object.assign(el.style, charset.style);
}
target.appendChild(el);
}
charsets.push(charset);
});
}
function charsetNextLoopStep(charset) {
charset.i = charset.i || 0;
charset.element.textContent = charset.parts[charset.i];
charset.i += reverse ? -1 : 1;
charset.i %= charset.parts.length;
if (charset.i < 0) {
charset.i += charset.parts.length;
}
}
var af;
var af_to;
function tick(timestamp) {
charsets.forEach((charset) => {
charsetNextLoopStep(charset);
});
if (running)...