diff --git a/explorer.js b/explorer.js index 80860d01..b761cd62 100644 --- a/explorer.js +++ b/explorer.js @@ -1,12 +1,13 @@ -var VERSION = '2.0'; -var getCharDataUrl = (char) => `https://cdn.jsdelivr.net/npm/hanzi-writer-data@${VERSION}/${char}.json`; +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.overrideMimeType("application/json"); } - xhr.open('GET', getCharDataUrl(char), true); + xhr.open("GET", getCharDataUrl(char), true); xhr.onreadystatechange = () => { if (xhr.readyState !== 4) return; if (xhr.status === 200) { @@ -16,67 +17,93 @@ function loadData(char, onLoad, onError) { } }; 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); + return document.createElementNS("http://www.w3.org/2000/svg", elmType); +} + +function getPathString(points) { + const start = points[0]; + const remainingPoints = points.slice(1); + let pathString = `M ${start[0]} ${start[1]}`; + remainingPoints.forEach(point => { + pathString += ` L ${point[0]} ${point[1]}`; + }); + return pathString; } 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%'); + 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)'); + 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); + var path = createElm("path"); + attr(path, "d", stroke); + path.classList.toggle("radical-stroke", isRadical); + group.appendChild(path); + }); + charData.medians.forEach(median => { + var path = createElm("path"); + attr(path, "d", getPathString(median)); + path.classList.add("median-stroke"); 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); + var target = document.querySelector("#target"); + var transparent = document.querySelector("#transparent").checked; + var radical = document.querySelector("#radical").checked; + var medians = document.querySelector("#medians").checked; + target.classList.toggle("transparent-strokes", transparent); + target.classList.toggle("color-radical", radical); + target.classList.toggle("show-medians", medians); } -document.querySelectorAll('input[type=checkbox]').forEach(function(node) { - node.addEventListener('change', updateClasses); +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) + var cdnTarget = document.querySelector("#cdn-path"); + var url = getCharDataUrl(char); cdnTarget.innerHTML = `${url}`; - var npmTarget = document.querySelector('#npm-path'); + 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}`); - }); + 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) { @@ -88,16 +115,15 @@ function setCharFromHash(defaultChar) { } } if (hashChar) { - document.querySelector('#char-input').value = hashChar; + document.querySelector("#char-input").value = hashChar; } } -setCharFromHash('我'); -window.addEventListener('hashchange', function() { +setCharFromHash("我"); +window.addEventListener("hashchange", function() { setCharFromHash(null); loadAndRender(); }); -document.querySelector('#update-char').addEventListener('click', loadAndRender); +document.querySelector("#update-char").addEventListener("click", loadAndRender); updateClasses(); loadAndRender(); - diff --git a/index.html b/index.html index 9d4f7b0d..1374534c 100644 --- a/index.html +++ b/index.html @@ -1,46 +1,82 @@ - - - Hanzi Writer Data Explorer - - - -

Hanzi Writer Data Explorer

+ + + 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. -

+

+ 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
+
-
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. +
-
- 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 index 55b7a898..fd6eb83f 100644 --- a/styles.css +++ b/styles.css @@ -1,123 +1,142 @@ -body, html { - background: #f4f0ea; - margin: 0; - padding: 0; - text-align: center; - font-size: 14px; - font-family: sans-serif; +body, +html { + background: #f4f0ea; + margin: 0; + padding: 0; + text-align: center; + font-size: 14px; + font-family: sans-serif; } body { - padding-bottom: 80px; + padding-bottom: 80px; } * { - box-sizing: border-box; + box-sizing: border-box; } -input, button { - outline: none; +input, +button { + outline: none; } -#target, .title, .controls, .cdn-path, .npm-path { - box-shadow: 0 1px 5px rgba(0,0,0,0.15); +#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; + max-width: 400px; + margin: 30px auto 50px; + line-height: 25px; } .title { - background: white; - padding: 15px 0; - margin: 0 0 30px; + 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; + 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; + 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; + display: flex; + justify-content: space-between; } .char-input { - padding: 5px; - margin-right: 5px; - font-size: 24px; - display: block; - flex-grow: 1; + padding: 5px; + margin-right: 5px; + font-size: 24px; + display: block; + flex-grow: 1; } .do-it { - margin-top: 50px; + 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; +.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; + font-family: monospace; } .license { - font-size: 12px; - max-width: 600px; - margin: 50px auto 0; + font-size: 12px; + max-width: 600px; + margin: 50px auto 0; } -.license, .license a { - color: #999; - text-shadow: 1px 1px 0 white; +.license, +.license a { + color: #999; + text-shadow: 1px 1px 0 white; } .controls label { - display: block; - margin: 5px 0; + display: block; + margin: 5px 0; } path { - fill: #555; - stroke: #000; - stroke-width: 0; - transition: all 500ms; + fill: #555; + stroke: #000; + stroke-width: 0; + transition: all 500ms; } .transparent-strokes path { - fill: rgba(0,0,0,0.4); - stroke-width: 2px; + fill: rgba(0, 0, 0, 0.4); + stroke-width: 2px; +} + +path.median-stroke { + fill: none; + stroke: rgba(0, 0, 0, 0.4); + stroke-width: 3px; + opacity: 0; +} + +.show-medians path.median-stroke { + opacity: 1; } .radical-control { - color: #AAA; + color: #aaa; } .has-radical-data .radical-control { - color: initial; + color: initial; } .color-radical .radical-stroke { - fill: rgb(22, 110, 22); + fill: rgb(22, 110, 22); } .transparent-strokes.color-radical .radical-stroke { - fill: rgba(22, 110, 22, 0.4); + fill: rgba(22, 110, 22, 0.4); }