1
0
mirror of https://github.com/chanind/hanzi-writer-data.git synced 2025-07-19 15:28:54 +08:00

setting up a character data explorer

This commit is contained in:
David Chanin 2018-02-21 23:30:06 +08:00
commit dd33af7831
3 changed files with 272 additions and 0 deletions

103
explorer.js Normal file
View File

@ -0,0 +1,103 @@
var VERSION = '2.0';
var getCharDataUrl = (char) => `https://cdn.jsdelivr.net/npm/hanzi-writer-data@${VERSION}/${char}.json`;
function loadData(char, onLoad, onError) {
var xhr = new XMLHttpRequest();
if (xhr.overrideMimeType) {
xhr.overrideMimeType('application/json');
}
xhr.open('GET', getCharDataUrl(char), true);
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4) return;
if (xhr.status === 200) {
onLoad(JSON.parse(xhr.responseText));
} else if (onError) {
onError(xhr);
}
};
xhr.send(null);
};
function attr(elm, name, value) {
elm.setAttributeNS(null, name, value);
}
function createElm(elmType) {
return document.createElementNS('http://www.w3.org/2000/svg', elmType);
}
function renderCharacter(charData) {
var target = document.querySelector('#target');
document.body.classList.toggle('has-radical-data', !!charData.radStrokes);
target.innerHTML = '';
var svg = createElm('svg');
attr(svg, 'width', '100%');
attr(svg, 'height', '100%');
target.appendChild(svg);
var group = createElm('g');
attr(group, 'transform', 'translate(0, 263.671875) scale(0.29296875, -0.29296875)');
svg.appendChild(group);
charData.strokes.forEach((stroke, i) => {
var isRadical = (charData.radStrokes || []).indexOf(i) > -1;
var path = createElm('path');
attr(path, 'd', stroke);
path.classList.toggle('radical-stroke', isRadical);
group.appendChild(path);
});
}
function updateClasses() {
var target = document.querySelector('#target');
var transparent = document.querySelector('#transparent').checked;
var radical = document.querySelector('#radical').checked;
target.classList.toggle('transparent-strokes', transparent);
target.classList.toggle('color-radical', radical);
}
document.querySelectorAll('input[type=checkbox]').forEach(function(node) {
node.addEventListener('change', updateClasses);
});
function renderLoadPath(char) {
var cdnTarget = document.querySelector('#cdn-path');
var url = getCharDataUrl(char)
cdnTarget.innerHTML = `<a href="${url}" target="blank">${url}</a>`;
var npmTarget = document.querySelector('#npm-path');
npmTarget.innerHTML = `var charData = require('hanzi-writer-data/${char}.json');`;
}
function loadAndRender() {
var char = document.querySelector('#char-input').value;
loadData(char, function(charData) {
renderCharacter(charData);
renderLoadPath(char);
window.location.hash = char.codePointAt(0);
}, function(err) {
console.error(err);
alert(`Unable to load data for ${char}`);
});
}
function setCharFromHash(defaultChar) {
var hashChar = defaultChar;
if (window.location.hash) {
var codePoint = parseInt(window.location.hash.slice(1));
if (!isNaN(codePoint)) {
hashChar = String.fromCodePoint(codePoint);
}
}
if (hashChar) {
document.querySelector('#char-input').value = hashChar;
}
}
setCharFromHash('我');
window.addEventListener('hashchange', function() {
setCharFromHash(null);
loadAndRender();
});
document.querySelector('#update-char').addEventListener('click', loadAndRender);
updateClasses();
loadAndRender();

46
index.html Normal file
View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<title>Hanzi Writer Data Explorer</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1 class="title">Hanzi Writer Data Explorer</h1>
<p class="description">
Explore the Chinese character SVG data used by <a href="https://chanind.github.io/hanzi-writer/">Hanzi Writer</a>. These stroke paths come from the <a href="https://github.com/skishore/makemeahanzi">Make me a Hanzi</a> project.
</p>
<div class="controls char-input-controls">
<input type="text" class="char-input" id="char-input" size="1" maxlength="1" />
<button type="submit" id="update-char">Update</button>
</div>
<div id="target">
</div>
<div class="controls">
<label>
<input type="checkbox" checked name="transparent" id="transparent" value="1" />
Transparent strokes
</label>
<label class="radical-control">
<input type="checkbox" checked name="radical" id="radical" value="1" />
Color radical
</label>
</div>
<div class="do-it">Load this data via CDN</div>
<div class="cdn-path" id="cdn-path"></div>
<div>Or via NPM</div>
<div class="npm-path" id="npm-path"></div>
<div class="license">
The Character data Hanzi Writer uses is from the <a href="https://github.com/skishore/makemeahanzi">Make Me A Hanzi</a> project, which extracted the data from fonts by <a href="http://www.arphic.com/">Arphic Technology</a>, a Taiwanese font forge that released their work under a permissive license in 1999. You can redistribute and/or modify this data (in the <a href="https://github.com/chanind/hanzi-writer-data">hanzi-writer-data</a> github repository) under the terms of the <a href="http://ftp.gnu.org/non-gnu/chinese-fonts-truetype/LICENSE">Arphic Public License</a> as published by Arphic Technology Co., Ltd. A copy of this license can also be found in <a href="https://raw.githubusercontent.com/chanind/hanzi-writer-data/master/ARPHICPL.TXT">ARPHICPL.TXT</a> of the hanzi-writer-data repo.
</div>
<script type="application/javascript" src="explorer.js"></script>
</body>
</html>

123
styles.css Normal file
View File

@ -0,0 +1,123 @@
body, html {
background: #f4f0ea;
margin: 0;
padding: 0;
text-align: center;
font-size: 14px;
font-family: sans-serif;
}
body {
padding-bottom: 80px;
}
* {
box-sizing: border-box;
}
input, button {
outline: none;
}
#target, .title, .controls, .cdn-path, .npm-path {
box-shadow: 0 1px 5px rgba(0,0,0,0.15);
}
.description {
max-width: 400px;
margin: 30px auto 50px;
line-height: 25px;
}
.title {
background: white;
padding: 15px 0;
margin: 0 0 30px;
}
#target {
background: white;
clear: both;
border: 1px solid black;
width: 300px;
height: 300px;
margin: 0 auto;
}
.controls {
width: 300px;
padding: 5px;
background: white;
border: 1px solid black;
margin: 5px auto;
text-align: left;
}
.char-input-controls {
display: flex;
justify-content: space-between;
}
.char-input {
padding: 5px;
margin-right: 5px;
font-size: 24px;
display: block;
flex-grow: 1;
}
.do-it {
margin-top: 50px;
}
.cdn-path, .npm-path {
max-width: 600px;
background: white;
padding: 10px 30px;
margin: 20px auto 40px;
display: inline-block;
user-select: all;
}
.npm-path {
font-family: monospace;
}
.license {
font-size: 12px;
max-width: 600px;
margin: 50px auto 0;
}
.license, .license a {
color: #999;
text-shadow: 1px 1px 0 white;
}
.controls label {
display: block;
margin: 5px 0;
}
path {
fill: #555;
stroke: #000;
stroke-width: 0;
transition: all 500ms;
}
.transparent-strokes path {
fill: rgba(0,0,0,0.4);
stroke-width: 2px;
}
.radical-control {
color: #AAA;
}
.has-radical-data .radical-control {
color: initial;
}
.color-radical .radical-stroke {
fill: rgb(22, 110, 22);
}
.transparent-strokes.color-radical .radical-stroke {
fill: rgba(22, 110, 22, 0.4);
}