commit dd33af7831331754de4b8991d36cac9f7d22f416 Author: David Chanin Date: Wed Feb 21 23:30:06 2018 +0800 setting up a character data explorer diff --git a/explorer.js b/explorer.js new file mode 100644 index 00000000..80860d01 --- /dev/null +++ b/explorer.js @@ -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 = `${url}`; + + 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(); + diff --git a/index.html b/index.html new file mode 100644 index 00000000..9d4f7b0d --- /dev/null +++ b/index.html @@ -0,0 +1,46 @@ + + + + + Hanzi Writer Data Explorer + + + +

Hanzi Writer Data Explorer

+ +

+ Explore the Chinese character SVG data used by Hanzi Writer. These stroke paths come from the Make me a Hanzi project. +

+ +
+ + +
+ +
+ +
+
+ + +
+ +
Load this data via CDN
+
+
Or via NPM
+
+ +
+ The Character data Hanzi Writer uses is from the Make Me A Hanzi project, which extracted the data from fonts by Arphic Technology, a Taiwanese font forge that released their work under a permissive license in 1999. You can redistribute and/or modify this data (in the hanzi-writer-data github repository) under the terms of the Arphic Public License as published by Arphic Technology Co., Ltd. A copy of this license can also be found in ARPHICPL.TXT of the hanzi-writer-data repo. +
+ + + + + \ No newline at end of file diff --git a/styles.css b/styles.css new file mode 100644 index 00000000..55b7a898 --- /dev/null +++ b/styles.css @@ -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); +}