ah, that did it! thanks for the help!!
Okay, bit of a script noob here. Iāve downloaded and it works perfectly in kanji previews, but doesnāt appear at all in lessons. Anyone know whatās going on?
Iāll look into it when I get some kanji lessons on my test account
@Wanimekani remindme 115m āReview on test accountā
Sorry to be a pain, Iāve only just realised itās for kanji only! I think I was looking at vocabulary and getting confused, as it worked great in my kanji lessons today. Sorry for the confusion!
Thank you so much! I was wondering why the script was not working anymore.
The script was not loading today so I checked all the GM/FF compatibility options in Edit script > Externals ā¦ and now it works but I have no clue what these options doā¦ Just posting this in case someone has a similar issue.
So, I have kind of a weird error.
I am using userscripts through violentmonkey on android kiwi browser and most userscripts work fine.
This one was working fine as well if used directly in the browser, but if I add Wanikani to my home screen as a shortcut and open it there, the diagrams donāt load, but no error message is thrown. It just stays white where the diagrams are supposed to be.
Anyone has an idea what could cause this?
Do you have access to a developer console to see if there are any errors?
Thanks for maintaining this Kumirei. I only noticed today after getting å radical in lessons and wanting to know the stroke order but the kanji page didnāt have it. Now it shows up.
If someone writes using brush pen (like me) or simply wants to see how kanji looks like in different fonts here is how I did it.
Maybe someone will find it useful.
And if thereās a problem with jisho.org you can temporarily add font with inline stroke numbers.
Add those lines to script (start from bottom so numbers donāt shift) and choose local fonts (previewFonts) you want to display.
// line 131
let previewFonts = ["EPSON ęē§ęøä½ļ¼", "nagayama_kai"];
let previewSize = "200px";
let kanjiCur = getKanji();
let previewItems = previewFonts.reduce(
(acc, cur) =>
acc +
`<div style="
display: inline-block;
margin-right:5px;
border:1px solid black;
color:black;
text-align:center;
width:${previewSize};
height:${previewSize};
line-height:${previewSize};
font-size:${previewSize};
font-family:'${cur}',serif;
">
${kanjiCur}
</div>`,
""
);
let preview = `<div id="preview" style="margin-bottom:5px;">${previewItems}</div>`;
// line 132
// line 133 (substitute)
`<section><h2>Stroke Order</h2>${preview}<div style="width:100%;overflow-x: auto; overflow-y: hidden"><svg id="stroke_order"></svg></div></section>`;
// line 133
// line 156
let previewNode = $("#preview")[0];
if (previewNode)
previewNode.childNodes.forEach((e) => {
e.textContent = getKanji();
});
// line 157
Just wanted to say thank you for this script! I donāt have to go back and forth between sources now.
I noticed today that Iām having an issue where the stroke order diagram isnāt showing up on kanji lessons at all. Everything seems normal on my end though, so I thought I should bring it up here.
EDIT: Aaaaand now of course after making a post, it magically came back. Sometimes all you need to do is complain, it seems.
@Kumirei This script seems to be affected by the change of lessons to React. As you have already seen (since you replied to my post last week), I have recently created a library script that simplifies injecting additional item info. Sadly, I didnāt have time yet to write a documentation for it. Should I try to modify this script to use WK Item Info Injector?
This script seems to be affected by the change of lessons to React.
Ah, I havenāt had time to look into which scripts would be affected yet!
Should I try to modify this script to use WK Item Info Injector?
That would be great!
I didnāt anticipate that someone wants to insert elements above all other sections when I designed WK Item Info Injector, so I had to add a small workaround for the review and lessonQuiz.
Code
// ==UserScript==
// @name WaniKani Stroke Order
// @namespace japanese
// @version 1.1.8
// @description Shows a kanji's stroke order on its page and during lessons and reviews.
// @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
// @include http*://*wanikani.com/kanji/*
// @include http*://*wanikani.com/level/*/kanji/*
// @include http*://*wanikani.com/review/session
// @include http*://*wanikani.com/lesson/session
// @author Looki, maintained by Kumirei
// @grant GM_xmlhttpRequest
// @connect jisho.org
// @connect cloudfront.net
// @require https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js
// @require https://greasyfork.org/scripts/430565-wanikani-item-info-injector/code/WaniKani%20Item%20Info%20Injector.user.js?version=962341
// ==/UserScript==
/*
* Thanks a lot to ...
* Wanikani Phonetic-Semantic Composition - Userscript
* by ruipgpinheiro (LordGravewish)
* ... for code showing me how to insert sections during kanji reviews.
* The code heavily borrows from that script!
* Also thanks to Halo for a loading bug fix!
*/
;(function () {
/* global Snap */
/*
* Helper Functions/Variables
*/
let wkItemInfo = unsafeWindow.wkItemInfo
/*
* Global Variables/Objects/Classes
*/
const JISHO = 'https://jisho.org'
const strokeOrderCss =
'.stroke_order_diagram--bounding_box {fill: none; stroke: #ddd; stroke-width: 2; stroke-linecap: square; stroke-linejoin: square;}' +
'.stroke_order_diagram--bounding_box {fill: none; stroke: #ddd; stroke-width: 2; stroke-linecap: square; stroke-linejoin: square;}' +
'.stroke_order_diagram--existing_path {fill: none; stroke: #aaa; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round;}' +
'.stroke_order_diagram--current_path {fill: none; stroke: #000; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round;}' +
'.stroke_order_diagram--path_start {fill: rgba(255,0,0,0.7); stroke: none;}' +
'.stroke_order_diagram--guide_line {fill: none; stroke: #ddd; stroke-width: 2; stroke-linecap: square; stroke-linejoin: square; stroke-dasharray: 5, 5;}'
init()
/*
* Main
*/
function init() {
wkItemInfo.on('lesson').forType('kanji').under('composition').append('Stroke Order', loadDiagram)
wkItemInfo.on('lessonQuiz, review,itemPage').forType('kanji').under('composition').appendAtTop('Stroke Order', loadDiagram)
let style = document.createElement('style')
style.textContent = strokeOrderCss
document.head.appendChild(style)
}
function xmlHttpRequest(urlText) {
return new Promise((resolve, reject) => GM_xmlhttpRequest({
method: 'GET',
url: new URL(urlText),
onload : xhr => { xhr.status === 200 ? resolve(xhr) : reject(xhr.responseText) },
onerror: xhr => { reject(xhr.responseText) }
}))
}
/*
* Adds the diagram section element to the appropriate location
*/
async function loadDiagram(injectorState) {
let xhr = await xmlHttpRequest(JISHO + '/search/' + injectorState.characters + '%20%23kanji')
let strokeOrderSvg = xhr.responseText.match(/var url = '\/\/(.+)';/)
if (!strokeOrderSvg) return null
xhr = await xmlHttpRequest('https://' + strokeOrderSvg[1])
let namespace = 'http://www.w3.org/2000/svg'
let div = document.createElement('div')
let svg = document.createElementNS(namespace, 'svg')
svg.id = 'stroke_order'
div.style = 'width: 100%; overflow: auto hidden;'
new strokeOrderDiagram(svg, xhr.responseXML || new DOMParser().parseFromString(xhr.responseText, "application/xml"))
div.append(svg)
return div
}
/*
* Lifted from jisho.org
*/
var strokeOrderDiagram = function (element, svgDocument) {
var s = Snap(element)
var diagramSize = 200
var coordRe = '(?:\\d+(?:\\.\\d+)?)'
var strokeRe = new RegExp('^[LMT]\\s*(' + coordRe + ')[,\\s](' + coordRe + ')', 'i')
var f = Snap(svgDocument.getElementsByTagName('svg')[0])
var allPaths = f.selectAll('path')
var drawnPaths = []
var canvasWidth = (allPaths.length * diagramSize) / 2
var canvasHeight = diagramSize / 2
var frameSize = diagramSize / 2
var frameOffsetMatrix = new Snap.Matrix()
frameOffsetMatrix.translate(-frameSize / 16 + 2, -frameSize / 16 + 2)
// Set drawing area
s.node.style.width = canvasWidth + 'px'
s.node.style.height = canvasHeight + 'px'
s.node.setAttribute('viewBox', '0 0 ' + canvasWidth + ' ' + canvasHeight)
// Draw global guides
var boundingBoxTop = s.line(1, 1, canvasWidth - 1, 1)
var boundingBoxLeft = s.line(1, 1, 1, canvasHeight - 1)
var boundingBoxBottom = s.line(1, canvasHeight - 1, canvasWidth - 1, canvasHeight - 1)
var horizontalGuide = s.line(0, canvasHeight / 2, canvasWidth, canvasHeight / 2)
boundingBoxTop.attr({ class: 'stroke_order_diagram--bounding_box' })
boundingBoxLeft.attr({ class: 'stroke_order_diagram--bounding_box' })
boundingBoxBottom.attr({ class: 'stroke_order_diagram--bounding_box' })
horizontalGuide.attr({ class: 'stroke_order_diagram--guide_line' })
// Draw strokes
var pathNumber = 1
allPaths.forEach(function (currentPath) {
var moveFrameMatrix = new Snap.Matrix()
moveFrameMatrix.translate(frameSize * (pathNumber - 1) - 4, -4)
// Draw frame guides
var verticalGuide = s.line(
frameSize * pathNumber - frameSize / 2,
1,
frameSize * pathNumber - frameSize / 2,
canvasHeight - 1,
)
var frameBoxRight = s.line(frameSize * pathNumber - 1, 1, frameSize * pathNumber - 1, canvasHeight - 1)
verticalGuide.attr({ class: 'stroke_order_diagram--guide_line' })
frameBoxRight.attr({ class: 'stroke_order_diagram--bounding_box' })
// Draw previous strokes
drawnPaths.forEach(function (existingPath) {
var localPath = existingPath.clone()
localPath.transform(moveFrameMatrix)
localPath.attr({ class: 'stroke_order_diagram--existing_path' })
s.append(localPath)
})
// Draw current stroke
currentPath.transform(frameOffsetMatrix)
currentPath.transform(moveFrameMatrix)
currentPath.attr({ class: 'stroke_order_diagram--current_path' })
s.append(currentPath)
// Draw stroke start point
var match = strokeRe.exec(currentPath.node.getAttribute('d'))
var pathStartX = match[1]
var pathStartY = match[2]
var strokeStart = s.circle(pathStartX, pathStartY, 4)
strokeStart.attr({ class: 'stroke_order_diagram--path_start' })
strokeStart.transform(moveFrameMatrix)
pathNumber++
drawnPaths.push(currentPath.clone())
})
}
})()
(the version number is not bumped yet)
I have tested this version with Edge (Tampermonkey, Violentmonkey) and Firefox (Tampermonkey).
EDIT: Coincidentally, the newest version of WK Item Info Injector supports inserting elements at the top, so I updated the code to use this functionality.
I just noticed that you also match http*://*wanikani.com/level/*/kanji/*
ā I donāt remember encountering such an URL before, but it seems to still work: https://www.wanikani.com/level/1/kanji/å·„. Is it possible to reach such an URL through the current WK interface? Because WK Item Info Injector cannot handle it if the URL also contains /level/1
(it doesnāt do anything in that case).
Now that Iām thinking about it, WK Item Info Injector can be tricked into thinking it is on an item page by appending a /
after radicals/kanji/vocabulary (https://www.wanikani.com/kanji/), causing it to throws errors. I donāt think this URL is reachable through the UI ā that only leads to https://www.wanikani.com/kanji?difficulty=pleasant. But maybe I should address this issue anyway? However, itās not even sufficient to check if there is something after the /
, because https://www.wanikani.com/kanji/# or https://www.wanikani.com/kanji/? would still cause problems.
I feel like I opened Pandoraās box.
Is it possible to reach such an URL through the current WK interface?
I am not able to find any way to get there, so itās probably safe to remove
But maybe I should address this issue anyway? However, itās not even sufficient to check if there is something after the
/
I donāt think itās really that important to account for. While someone might delete the kanji from the URL in an attempt to get back to the kanji page, the probability of someone doing so is low enough that I think it would be more effort for you to cover that possibility than it would be for those people to deal with whatever it caused. Although I assume it would just throw an error and not be noticeable at all?
Yes, the only effect is that it throws a bunch of errors in the console. I will probably put it really low on my to-do list.
Hi there!
The stroke order isnāt showing up in kanji lessons like @EvilScheme mentioned. I can see youāre discussing it but I have no idea what your discussions mean, but looks like itās not an easy fix?
Does it mean it wonāt come back soon?
Their issue resolved itself. Did yours?