-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Show stroke order of kanji #69
Comments
Sounds like a good idea. There are a few other higher-priority items I need to work on first, however. |
This can be a very useful thing for learners. |
Thanks for bumping this. Perhaps an interaction where you hover over the character or some area near the character would work. |
My suggestion would be, that the numbers will actually be displayed by default. I think, they don't really bother too much, even if you're not interested in the information. Or do they @SaltfishAmi? |
It's hard to say for now, it depends on the actual appearance of numbers. And for the numbers, I think we need to consider thoroughly about how to keep a clean view of the character itself. For example, there are some kanjis that are already packed with strokes, like this one: To add stroke order numbers without obscuring the kanji itself seems a complex task. What makes it worse is that most kanjis that I will need to look up are complex ones like this one, because as a Chinese I'm already familiar with all basic kanjis. |
Kanji stroke order could show up on click/tap on the Kanji itself, or on the "x strokes" label, leaving the regular look in place by default. That would be a neat compromise, since even if you're a learner who's interested in stroke order, most of the time you only need to see it when you're unsure in one spot and need a reminder, or for a really rare outlier Kanji where stroke order cannot be inferred. |
Yeah, I see how some people really wouldn't like this kind of messy display by default. |
fwiw I imagined something like this. The animation could be triggered by a mouse click. cut.webm |
Aside from the visual design decisions, how would we want to integrate the KanjiVG dataset into this project? The folder containing the seperate SVG files is approximately 53MB in size (or ~22MB when zipped). The three options coming to my mind are (from what I feel is worst to best but I'm really not sure):
What are your thoughts on these approaches, or do you have any other suggestions for integrating the dataset efficiently? |
@enellis Thanks for raising this! Animating SVGs is a topic dear to my heart (I've spent most of my career working on it!) so I'm looking forward to integrating this. The timing is also very good since we just shipped 1.19 which, thanks to @StarScape, includes the first steps towards rebuilding the popup code using Preact which will make adding interactivity to the kanji tab a lot easier. UX thoughtsRegarding the UX, I think we've mostly converged on the following features:
The tricky part is that clicking the kanji currently brings up the "Copy to clipboard" overlay so we would need to either:
Handling the KanjiVG dataRegarding the KanjiVG data set I had a quick look now. Taking the very first file there, <?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2009/2010/2011 Ulrich Apel.
This work is distributed under the conditions of the Creative Commons
Attribution-Share Alike 3.0 Licence. This means you are free:
* to Share - to copy, distribute and transmit the work
* to Remix - to adapt the work
Under the following conditions:
* Attribution. You must attribute the work by stating your use of KanjiVG in
your own copyright header and linking to KanjiVG's website
(http://kanjivg.tagaini.net)
* Share Alike. If you alter, transform, or build upon this work, you may
distribute the resulting work only under the same or similar license to this
one.
See http://creativecommons.org/licenses/by-sa/3.0/ for more details.
-->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd" [
<!ATTLIST g
xmlns:kvg CDATA #FIXED "http://kanjivg.tagaini.net"
kvg:element CDATA #IMPLIED
kvg:variant CDATA #IMPLIED
kvg:partial CDATA #IMPLIED
kvg:original CDATA #IMPLIED
kvg:part CDATA #IMPLIED
kvg:number CDATA #IMPLIED
kvg:tradForm CDATA #IMPLIED
kvg:radicalForm CDATA #IMPLIED
kvg:position CDATA #IMPLIED
kvg:radical CDATA #IMPLIED
kvg:phon CDATA #IMPLIED >
<!ATTLIST path
xmlns:kvg CDATA #FIXED "http://kanjivg.tagaini.net"
kvg:type CDATA #IMPLIED >
]>
<svg xmlns="http://www.w3.org/2000/svg" width="109" height="109" viewBox="0 0 109 109">
<g id="kvg:StrokePaths_0f9a8" style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;">
<g id="kvg:0f9a8" kvg:element="令">
<g id="kvg:0f9a8-g1" kvg:element="人" kvg:position="top" kvg:radical="general">
<path id="kvg:0f9a8-s1" kvg:type="㇒" d="M49.62,13.25c0.11,0.94,0.38,2.48-0.22,3.77c-4.15,8.86-15.15,25.23-36.65,37.08"/>
<path id="kvg:0f9a8-s2" kvg:type="㇏" d="M50.54,16.55c6.13,4.35,24.99,20.22,33.98,27.33c3.22,2.54,5.6,4.12,9.73,5.37"/>
</g>
<g id="kvg:0f9a8-g2" kvg:position="bottom">
<g id="kvg:0f9a8-g3" kvg:element="一">
<path id="kvg:0f9a8-s3" kvg:type="㇐" d="M 38.590625,42.910833 c 1.76,0.72 3.84,0.36 5.65,0.14 5.4,-0.66 13.08,-1.76 18.48,-2.24 1.88,-0.17 3.54,-0.23 5.37,0.21"/>
</g>
<g id="kvg:0f9a8-g4" kvg:element="卩" kvg:original="マ">
<path id="kvg:0f9a8-s4" kvg:type="㇆" d="M 31.464375,53.641042 c 0.61,0.15 3,1 4.21,0.87 10.329583,-0.937708 28.549375,-2.998125 38.130833,-4.17 1.516086,-0.185427 4.278829,-0.290121 3.95,2.89 -0.431171,4.169879 -2.680149,16.919928 -6,23.84 -1.890149,3.939928 -3.18,3.45 -6.23,0.46"/>
<path id="kvg:0f9a8-s5" kvg:type="㇑" d="M 44.769166,53.809375 c 0.87,0.87 1.8,2 1.8,3.5 0,7.36 -0.04,24.53 -0.1,34.13 -0.02,3.3 -0.05,5.71 -0.08,6.51"/>
</g>
</g>
</g>
</g>
<g id="kvg:StrokeNumbers_0f9a8" style="font-size:8;fill:#808080">
<text transform="matrix(1 0 0 1 42.50 15.13)">1</text>
<text transform="matrix(1 0 0 1 58.50 19.63)">2</text>
<text transform="matrix(1 0 0 1 43 40)">3</text>
<text transform="matrix(1 0 0 1 25.1 62.1)">4</text>
<text transform="matrix(1 0 0 1 36.4 65.5)">5</text>
</g>
</svg> The draw me a kanji source appears to only use the <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 109 109">
<g id="kvg:StrokePaths_0f9a8" style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;">
<g id="kvg:0f9a8">
<g id="kvg:0f9a8-g1">
<path id="kvg:0f9a8-s1" d="M49.62,13.25c0.11,0.94,0.38,2.48-0.22,3.77c-4.15,8.86-15.15,25.23-36.65,37.08"/>
<path id="kvg:0f9a8-s2" d="M50.54,16.55c6.13,4.35,24.99,20.22,33.98,27.33c3.22,2.54,5.6,4.12,9.73,5.37"/>
</g>
<g id="kvg:0f9a8-g2">
<g id="kvg:0f9a8-g3">
<path id="kvg:0f9a8-s3" d="M 38.590625,42.910833 c 1.76,0.72 3.84,0.36 5.65,0.14 5.4,-0.66 13.08,-1.76 18.48,-2.24 1.88,-0.17 3.54,-0.23 5.37,0.21"/>
</g>
<g id="kvg:0f9a8-g4">
<path id="kvg:0f9a8-s4" d="M 31.464375,53.641042 c 0.61,0.15 3,1 4.21,0.87 10.329583,-0.937708 28.549375,-2.998125 38.130833,-4.17 1.516086,-0.185427 4.278829,-0.290121 3.95,2.89 -0.431171,4.169879 -2.680149,16.919928 -6,23.84 -1.890149,3.939928 -3.18,3.45 -6.23,0.46"/>
<path id="kvg:0f9a8-s5" d="M 44.769166,53.809375 c 0.87,0.87 1.8,2 1.8,3.5 0,7.36 -0.04,24.53 -0.1,34.13 -0.02,3.3 -0.05,5.71 -0.08,6.51"/>
</g>
</g>
</g>
</g>
</svg> We don't need to repeat the styling information in each file and if it turns out we don't need the grouping or the path IDs we could reduce this down to just: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 109 109">
<path d="M49.62,13.25c0.11,0.94,0.38,2.48-0.22,3.77c-4.15,8.86-15.15,25.23-36.65,37.08"/>
<path d="M50.54,16.55c6.13,4.35,24.99,20.22,33.98,27.33c3.22,2.54,5.6,4.12,9.73,5.37"/>
<path d="M 38.590625,42.910833 c 1.76,0.72 3.84,0.36 5.65,0.14 5.4,-0.66 13.08,-1.76 18.48,-2.24 1.88,-0.17 3.54,-0.23 5.37,0.21"/>
<path d="M 31.464375,53.641042 c 0.61,0.15 3,1 4.21,0.87 10.329583,-0.937708 28.549375,-2.998125 38.130833,-4.17 1.516086,-0.185427 4.278829,-0.290121 3.95,2.89 -0.431171,4.169879 -2.680149,16.919928 -6,23.84 -1.890149,3.939928 -3.18,3.45 -6.23,0.46"/>
<path d="M 44.769166,53.809375 c 0.87,0.87 1.8,2 1.8,3.5 0,7.36 -0.04,24.53 -0.1,34.13 -0.02,3.3 -0.05,5.71 -0.08,6.51"/>
</svg> That works out at 749 bytes as opposed 3,031 bytes for the original which is a reduction of about 75%. We could reduce the precision of the path data using SVGO and get that down to 588 bytes for a total reduction of over 80%. Assuming the other characters can be reduced similarly, we could get the total uncompressed storage from 50Mb to 10~12Mb or so. Obviously the XPI file packaging will further compress that to something more manageable. I think those numbers line up pretty closely with the XML file you mentioned. Where is that XML file, by the way? Bundling the dataWe already bundle a 30Mb data file for the flat file dictionary, so I think bundling an extra 14Mb data file (or 14Mb of SVG files) for stroke order is probably reasonable. Users only download this data when the add-on is updated which is only every month or so and, once compressed, it's only the size of a large image anyway. So I think we can rule out your third option of loading off the network in the background. That leaves the other two options which I understand being:
Like you mentioned, (2) has the disadvantage of increasing the add-on's memory footprint, at least for the background script. It's also probably more code overall and more states to manage. As a result, I think (1) is worth a try. I'd prefer to write our own animation code rather than incorporating another library to avoid cruft and because I think we can do better. For example, draw me a kanji introduces a dependency on Raphael and kanjivganimate relies on setTimeout which is known to be problematic for synchronizing animations. Given that we are going to be parsing out the path data anyway, it might not even be necessary to store the characters as SVG files. They could possibly even just be JSON files with an array of SVG path data strings. |
@birtles Thank you for your detailed response. I truly appreciate your dedication to this project and want to thank you for the continuous effort you put into it, especially considering that you do this for free. UX
KanjiVGThe XML file I referred to is generated with each full release of the KanjiVG repository by a python script and can be found in the assets. For example, the entry for 令 would look like this: <kanji id="kvg:kanji_0f9a8">
<g id="kvg:0f9a8" kvg:element="令">
<g id="kvg:0f9a8-g1" kvg:element="人" kvg:position="top" kvg:radical="general">
<path id="kvg:0f9a8-s1" kvg:type="㇒" d="M49.62,13.25c0.11,0.94,0.38,2.48-0.22,3.77c-4.15,8.86-15.15,25.23-36.65,37.08"/>
<path id="kvg:0f9a8-s2" kvg:type="㇏" d="M50.54,16.55c6.13,4.35,24.99,20.22,33.98,27.33c3.22,2.54,5.6,4.12,9.73,5.37"/>
</g>
<g id="kvg:0f9a8-g2" kvg:position="bottom">
<g id="kvg:0f9a8-g3" kvg:element="一">
<path id="kvg:0f9a8-s3" kvg:type="㇐" d="M 38.590625,42.910833 c 1.76,0.72 3.84,0.36 5.65,0.14 5.4,-0.66 13.08,-1.76 18.48,-2.24 1.88,-0.17 3.54,-0.23 5.37,0.21"/>
</g>
<g id="kvg:0f9a8-g4" kvg:element="卩" kvg:original="マ">
<path id="kvg:0f9a8-s4" kvg:type="㇆" d="M 31.464375,53.641042 c 0.61,0.15 3,1 4.21,0.87 10.329583,-0.937708 28.549375,-2.998125 38.130833,-4.17 1.516086,-0.185427 4.278829,-0.290121 3.95,2.89 -0.431171,4.169879 -2.680149,16.919928 -6,23.84 -1.890149,3.939928 -3.18,3.45 -6.23,0.46"/>
<path id="kvg:0f9a8-s5" kvg:type="㇑" d="M 44.769166,53.809375 c 0.87,0.87 1.8,2 1.8,3.5 0,7.36 -0.04,24.53 -0.1,34.13 -0.02,3.3 -0.05,5.71 -0.08,6.51"/>
</g>
</g>
</g>
</kanji> A little bit more verbose compared to your proposed data reduction, but of course as you said, we could write our own tool to extract the data we need in the format that suits us best. |
@enellis, likewise thank you for your very helpful input here!
Great! I think once we've converted the kanji tab to Preact and have a React Cosmos fixture for it, it will be easier to prototype a play button.
I can see that. I still think it will be hard to present the numbers in a clear and attractive manner. What if, after the user presses "Play" to show the animation, we showed a scrubber underneath the animation that lets you skip back and forth in the animation so you can jump to the part you're interested in?
Great, thank you! I thought about this a bit more and I think another option might be just to incorporate the stroke data into our kanji database. We already have a mechanism for downloading the kanji data and updating it. The kanji data itself is the combination of a number of data sources (KANJIDIC, 漢検 data, education level data, WaniKani data, custom kanji component data, Conning reference data, etc.) that we merge together as part of a data pipeline that runs every day. If we merge the path data in as part of that job then we can re-use all our existing code for updating the data and looking it up. It would simply be another field attached to the kanji data that we pass from background script to content script. The main downside is that whole data pipeline is something I maintain on AWS and is not really in a format amenable to contributing at the moment so it would basically have to wait for me to integrate the data upstream before we could use it. |
The markers are a good idea. I wonder about the aesthetics of coloring the strokes, however. I was imagining something along the lines of @sorashi's mockup in #69 (comment) so that the final character is all one color. However, I noticed you used shades of green. That's an interesting idea. Maybe if we used shades of the same color it wouldn't look so bad. Alternatively (or as well as) we could probably render little thumbnail strokes inside the markers but they might be too small to be useful.
Thanks! I'll get to it! |
I don't even think that coloring the Kanji itself is necessary. Just coloring the markers inside the scrubber should be sufficient because, when learning to write Kanji, one quickly gets a sense of which radicals a Kanji is composed of and the general rules of thumb, like left-to-right, top-to-bottom, horizontal first, etc. By simply looking at the colored scrubber, users can already get an overview of where the part of the animation that interests them is located.
Good idea. Definitely worth a try, I think. |
That's good to hear. Was there any particular meaning behind the shades of green? |
Not really, I just thought that, like you already mentioned, shades of one color would look better and more streamlined than using completely different colors. The choice of color was kind of arbitrary. |
Here's what I've got so far: 2024-08-27_14-03-37.mp4Still to do:
We could also color the active stroke differently like in the original comment but that will require me finding suitable colors for all the different themes. |
Thinking about this some more, I think it might be simpler to just always show the SVG version when we have it, rather than fading between the static version and the animated version. Then we'd put a little play button beneath it to toggle the animation on and off. I think that would be more intuitive than clicking on the stroke count. |
Simplified it to always show the SVG version (when available and mouse interactivity is enabled) and toggle play state using a play button directly beneath the animation: 2024-08-29_12-25-58.mp4 |
Thank you for the feature addition. The update has already been released on Chrome, but not Firefox (my main browser) yet. |
Sorry about that. I submitted the extension to add-ons.mozilla.org some time ago but it was marked rejection pending, I think due to some confusion about some test files in the source archive. Unfortunately I didn't get a notification about it and only noticed last week. I submitted an updated version last Thursday or so and it just got approved so it should be available on Firefox now. |
Thank you so much for your work on this feature! It really turned out great and looks very nice, neatly integrated with the little slider. Interestingly, 齎 appears to be incorrect. There's an extra stroke that shouldn't be there, drawn simultaneously with the 6th stroke. Do you know whether this is an error in the SVG file? |
Thanks!
Oh right you are. That's almost definitely a bug in the preprocessing of the SVG files. I'll take a look next time I get near a computer. Thanks for reporting this! |
Ok, I've fixed this upstream and should be reflected next time your installation checks for a dictionary update. (The issue was incorrect handling of relative initial moveto commands with following implicit lineto commands.) |
KanjiVG (GitHub) is a collection of over 10,000 SVG images of kanji with stroke order. There are multiple projects that build upon it, including kanimaji and anikanjivg. These make it possible to animate the stroke order. I think it would be a nice and useful option to show that when looking up kanji.
GIF:
The text was updated successfully, but these errors were encountered: