Hey all, just wondering as I have a card template which randomly chooses one of the following alignments and I’d like to have a vertical text option too, but I don’t know how to implement it.
const alignments = ["justify","left","center","right"];
Thanks for the help
You could use CSS variables for that.
-
Start by moving the CSS which you currently have inside HTML tags (
<style>CSS</style>
) over to the “Styling” section of your template (for better separation between JS and CSS).
Edit: On second thought, you probably did that to include both on the screenshot, right? -
For the
.japanese
class, instead of
writing-mode: vertical-rl;
,
use
writing-mode: var(--writing-mode);
. -
For random alignments, instead of
alignment: left;
use
alignment: var(--alignment);
With a little script, you can randomly pick values from your arrays:
<script>
var writingModes = ["horizontal-tb", "vertical-lr"];
var alignments = ["justify","left","center","right"];
var randomWritingMode;
var randomAlignment;
if(globalThis.onUpdateHook) {
randomWritingMode = writingModes[Math.floor(Math.random() * writingModes.length)];
randomAlignment = alignments[Math.floor(Math.random() * alignments.length)];
document.documentElement.style.setProperty('--writing-mode', randomWritingMode);
document.documentElement.style.setProperty('--alignment', randomAlignment);
}
</script>
Edit: Using var
instead of const
. Works now.
The CSS variable will be set for the whole document and applied wherever you used it in your CSS.
Sorry if I sound stupid, but could you explain to me where exactly I’d need to modify this in the code I put in my other post? I can’t manage to make it work…Thanks
I’m currently testing that script because the way I wrote it might cause some trouble. Anki desktop and AnkiMobile don’t rebuild everything on each card like AnkiDroid does, so I am still not used to that dynamic way of handling things.
It’ll take a moment but I’ll get back to you and edit my script up there once I’m sure it’s good.
I have edited the script now. You can just insert the whole thing at the bottom of your front template, like this:
Regarding the stylesheet, you’ll just need to use the CSS variable names which are declared in the script, e.g. var(--alignment)
, instead of actual values, e.g. left
or right
.
Doesn’t seem to be working…I’m probably doing something wrong, putting my code on pastebin because it doesn’t paste correctly here: randomizing - Pastebin.com
You already had some of that functionality implemented. I extended my script to include the font-size too and removed it from your own script.
You also had some illegal values for the alignment. The ones in bold are not alignment-values:
[“justify”,“left”,“center”,“right”,“top”,“bottom”,“vertical horizontal”];
(you also didn’t separate vertical and horizontal with quotes)
For my method to work, you need to set something up like this within your “Styling” section:
Here’s a demo of my rework:
The font-size, alignment and writing-mode randomization should only be done once (on the front) in my opinion. So you should only include my script in the Front template. You could use Anki Persistence to share the random colors between front- and backside as well.
Is this what you wanted?
Click to see reworked template
<div id="yomis" hidden>
<p>
<div class="randomJapanese shuffle colorize">{{Expression}}</div>
{{#Traditional}}
<div class="randomTraditionalChinese shuffle colorize">{{Traditional}}</div>
{{/Traditional}}
{{#Simplified}}
<div class="randomSimplifiedChinese shuffle colorize">{{Simplified}}</div>
{{/Simplified}}
<div id="container"></div>
</p>
</div>
<script>
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
function setRandomBackgroundColor() {
const nightMode = document.body.classList.contains("night_mode");
document.body.style.background = randomHsl(!nightMode);
}
function randomHsl(lightColor) {
const hue = (Math.random() * 361) | 0;
const saturation = (50 + (Math.random() * 50)) | 0;
let lightness = (Math.random() * 35) | 0;
if (lightColor) {
lightness += 65;
}
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
}
function colorizeEachChar(element) {
const text = element.textContent;
const nightMode = document.body.classList.contains("night_mode");
const resultArray = [];
for (const char of text) {
if (/\S/.test(char)) {
resultArray.push(
`<span style="color: ${randomHsl(nightMode)};">${char}</span>`
);
} else {
resultArray.push(" ");
}
}
element.innerHTML = resultArray.join("");
}
setTimeout(() => {
// Randomize the color of each character
document.querySelectorAll(".colorize").forEach(colorizeEachChar);
// Randomize the order of the elements with the "shuffle" class
const fields = [...document.querySelectorAll(".shuffle")];
shuffleArray(fields);
const container = document.getElementById("container");
fields.forEach((fld, index) => {
if (index !== 0) {
container.appendChild(document.createElement("br"));
}
container.appendChild(fld);
});
// Randomize the background color
setRandomBackgroundColor();
// Un-hide the main container
yomis.hidden = false;
}, 0);
</script>
<script>
var writingModes = ["horizontal-tb", "vertical-lr"];
var alignments = ["justify","left","right","center"];
var randomFontSize;
var randomWritingMode;
var randomAlignment;
if(globalThis.onUpdateHook) {
randomFontSize = Math.floor(Math.random() * 20) + Math.floor(Math.random() * 20)+ Math.floor(Math.random() * 20) + 10;
randomWritingMode = writingModes[Math.floor(Math.random() * writingModes.length)];
randomAlignment = alignments[Math.floor(Math.random() * alignments.length)];
document.documentElement.style.setProperty('--random-font-size', randomFontSize + 'px');
document.documentElement.style.setProperty('--random-writing-mode', randomWritingMode);
document.documentElement.style.setProperty('--random-alignment', randomAlignment);
}
</script>
AWESOME! Seems to be working perfectly. Is there any way to make the text break in two so it isn’t one line of text and one has to scroll down to read it all?
This:
a a
a a
a a
a a
a a
Instead of this:
a
a
a
a
a
a
a
a
a
I have no experience with vertical writing, but I believe it would wrap automatically if you set a max-height (maybe 50vh) for the containing <div>
From Mozilla:
vertical-lr
- For
ltr
scripts, content flows vertically from top to bottom, and the next vertical line is positioned to the right of the previous line. Forrtl
scripts, content flows vertically from bottom to top, and the next vertical line is positioned to the left of the previous line.*
I’ll see if I can help you with that tomorrow.
Thanks, I’ll wait for your help tomorrow! If you’ve got time, I’d also like to know if it’s possible to have the vertical text on the right sometimes or in the center, like for example vertical-rl or something like that. Have a good day
.shuffle {
max-height: 80vh;
text-orientation: upright;
}
Edited. Thanks @hengiesel!
Seems to work. It will lead to a horizontal scroll bar for longer texts though:
Info: The unit vh
i used for max-height stands for a percentage of the viewbox height.
Just a side note: for Japanese text (Tategaki), you’d typically use:
writing-mode: vertical-rl;
text-orientation: upright;
This way alphabet letters still stand upright. You could just add text-orientation: upright;
to the .shuffle
class above, as it doesn’t affect the horizontal case.
Hey! Working wonderfully…Was wondering, is it possible to have two separate fields show up besides each other and not below?
First four characters is one field, the other four is another. I’d like them to be parallell to each other. Don’t know if this is possible. Another thing I was wondering is why vertical text doesn’t change positions, it always stays on the left side. Horizontal text changes though. Thanks for the enormous help
I think you’d want “shuffle” to be applied to
(or the outer