How to change default color of SVG in MathJax-Node - mathjax

I am using MathJax-node to generate SVGs of equations. I would like to change the default color, but so far nothing has worked.
I looked at this answer and tried
mjAPI.config({MathJax: {
styles: {
".MathJax_SVG, .MathJax_SVG_Display": {
fill: "#FFF",
stroke: "#FFF"
}
}}});
I also tried
mjAPI.config({MathJax: {
SVG: {color: "#0FF", fill: "#0F0", stroke: "#F00"}}});
and several variations, like including the styles under SVG, but so far nothing has worked.
I can work around this by setting the style from within the TeX expression, but I would prefer to be able to set a default configuration so I can process expressions without altering them.

MathJax-node wraps its output in a group with fill="currentColor stroke="currentColor" so that it inherits the color from the surrounding text. So one way to change the color would be to set the color of the container that will hold the SVG output. The configuration you give above would do that for MathJax in a browser, since MathJax surrounds its SVG output in a container with class="MathJax_SVG" or class="MathJax_SVG_Display"; but MathJax-node does not produce the container HTML elements that MathJax does, so there are no elements with class MathJax_SVG or MathJax_SVG_Display being generated. In any case, the styles are put into a stylesheet that would be added to the page, not used to add explicit styles to the SVG generated, so you would have to include that stylesheet into the page where the SVG output is being put in order for your configuration above to have an effect, even if the containers with the proper classes were being generated.
What you probably want, however, is to have the currentColor be some specific color instead, so that there is no inheriting of colors. Because SVG is a text-based image format, you can do that using a string replacement in your mathjax-node driver file. For example:
mjAPI.typeset({
math: "x+1",
format: "TeX",
svg: true,
useFontCache: false,
ex: 6, width: 100
}, function (data) {
if (!data.errors) {
console.log(data.svg.replace(/"currentColor"/g, '"red"'));
}
});
would set the color to red in the output.

Related

Best way to dynamically style svg marker elements

My question: Can svg <marker> elements inherit color from the <line> they are referenced on?
The background: I have a D3 graph that has different styled lines, and I want my lines to have arrows at the end.
So at the top of my <svg> I have const defs = svg.append('defs'); and then further along I generate my defs using a generator function:
function makeDefs(defs: Selection<SVGDefsElement, unknown, null, undefined>, color: string, status: string) {
const markerSize = 3
const start = defs.append
.append('marker')
.attr('id', `arrow-start-${color}-${status}`)
.attr('viewBox', '-5 -10 20 20')
.attr('markerWidth', markerSize)
.attr('markerHeight', markerSize)
.attr('orient', 'auto-start-reverse');
start
.append('path')
.attr(
'd',
status === 'PUBLISHED' ? customPaths.arrowLarge : customPaths.arrowSmall
)
.attr('stroke', color)
.attr('fill', color);
}
And use it like so:
makeDefs(defs, 'red', 'DRAFT');
And then I add the markers to my lines with:
// d3 code to draw the lines etc
line.attr(
'marker-start',
(d) =>
`url(
#arrow-start-${d.color}-${d.status}
)`
);
This all works great, my arrows have lines. But my current setup feels burdensome and clunky. I have about 20 colors and 3 statuses. With my current setup that would be 60 different:
makeDefs(defs, 'one-of-20-colors', 'one-of-3-statues');
My understanding of markers is that they can inherit color using the currentcolor attribute. Currently my <defs> sit up top underneath my main <svg> so any color inherited is inherited directly from that top level svg which is not what I want. The issue in my case is my <line> elements are the elements who's color I want to inherit, but according to the MDN docs <line>s cannot have <defs> as children, thus leaving me with the only option, of defining all my <defs> up front all at once.
Is there a trick or some attribute I'm missing here?
Any way to pass color to my marker when doing:
line.attr(
'marker-start',
(d) =>
`url(
#arrow-start-${d.color}-${d.status}
)`
);
?
For what is is worth, I'm currently wrapping all my <line>s in <g>. I suppose I could wrap them in <svg>s instead, and apply the fill and stroke there, and then define my <defs> per svg container? I tried this briefly and swapping the <g> for an <svg> broke a lot, but I'm not even sure if it would work, or be better for that matter.

SVG with size in px and percentage?

I'm trying to create an SVG element with a width defined by a percentage of the parent and a fixed value, say 50% + 20px. For normal html elements, in the CSS you can use calc(50% + 20px). Is there an equivalent way to do this for embedded SVGs? Specifically, I'm using snap.svg, though I'm not sure if this capability exists with SVGs in general.
EDIT:
Tried setting <svg> width with percentages and px, which I couldn't get to work. I tried both:
<svg width='calc(50% + 20px)'>...</svg>
<svg width='50% + 20px'>...</svg>
I also tried setting it in CSS:
svg {
width: calc(50% + 20px);
}
It should be possible with the upcoming SVG2 as width etc. become geometry properties and then you can style them with calc

getting text width in SVG prior to rendering

I want to put a rectangle around a text in SVG.
The height of the text is known to me (the font-size attribute of the text element). But the width is dependent on the actual content. Using getBBox() or getComputedTextLength() should work. But this only works after rendering.
Is there a way to specify that in an other way? For example defining the x and width attributes relative to other values? I didn't find anything like that in the SVG Spec.
Figuring where text ends presumably requires roughly the same underlying code path as the rendering itself implements - going through the width of each character based on the font and style, etc... As I am not aware the SVG standards define a method for directly getting this information without doing the actual full rendering, till such methods emerge or are reported here by others, the approach should be to render invisibly before doing the actual rendering.
You can do that in a hidden layer (z-index, opacity and stuff) or outside the visible viewport, whichever works best in experimentation. You just need to get the browser do the rendering to find out, so you render invisibly for that sake, then use getComputedTextLength()
I know this is old, but a few ideas:
If you can choose a mono-spaced font, you know your width by a simple constant multiplication with glyph count
If you are bound to proportional fonts, you can find an average glyph size, do the math as with mono-space, and leave enough padding. Alternatively you can fill the padding with text element textLength attribute. If the constant is chosen carefully, the results are not very displeasing.
EDIT: As matanster found it to be hacky
Predetermine glyph widths with getComputedTextLength() and build a lookup table. Downside is that it does not account for kerning, but if your cache size is not a problem, you can append glyph-pair widths to this lookup.
Going beyond that is to find some way to do server side rendering: Is there a way to perform server side rendering of SVG graphics using React?
It is possible using canvas with measureText():
// Get text width before rendering
const getTextWidth = (text, font) => {
const element = document.createElement('canvas');
const context = element.getContext('2d');
context.font = font;
return context.measureText(text).width;
}
// Demo
const font = '16px serif';
const text = 'My svg text';
const textWidth = getTextWidth(text, font);
document.body.innerHTML = `
<svg>
<text x="0" y="20" font="${font}">${text}</text>
<rect x="0" y="30" width="${textWidth}" height="4" fill="red" />
</svg>
`;
Adapted from https://stackoverflow.com/a/31305410/1657101

How do I change the style of the legend in Flot?

I have just changed my version of Flot from 0.6 to 0.7, however, when I do this, the legend in my Flot graph changes style. Previously, I had used the "LabelClass" attribute to change the style but on reading the source for 0.7 I see that "labelClass" is no longer an option and I appear to be forced to use the "table" CSS definition that is used throughout the site that I'm working on. Because of this I can't change the site's CSS "table" definition.
Is there another good method for changing the definition of a legend or am I stuck?
Apologies in advance is this is just a newbie question
Kind Regards
It has changed names is all, the new class is legendLabel for the labels and legendColorBox for the color box.
You can see this in jquery.flot.js.
EDIT in response, it seems that the question is how do you style the whole table. Assume your flot placeholder is something like this:
<div id="foo" style="width:600px;height:300px"></div>
Then you can define CSS like this:
#foo > div.legend > table {
border: 2px red solid;
}
See it here in action: http://jsfiddle.net/ryleyb/YkDpG/1/
Another way to style the legend is to use the jQuery .css() (http://api.jquery.com/css/) method after the chart has been plotted.
For example:
$.plot($("#chartFoo"), pieChartData, options);
$("#chartFoo div.legend table").css("border", "1px solid #888888");
$("#chartFoo div.legend table").css("background", "#ffffee");
or:
$.plot($("#chartFoo"), pieChartData, options);
$("#chartFoo div.legend table").css({ border: "1px solid #888888", background: "#ffffee" });

Is there an easy way to give a MediaWiki wiki page a specific background colour?

We're looking to give pages in a specific category a specific background colour. Since every page in this category makes use of a specific template, we're ideally looking for a template change.
Can this be done?
Use the PageCSS extension, you should be able to put the css in your template, which would then apply to the pages it is on.
example:
<css>
#bodyContent { background-color: yellow; }
</css>
For the MediaWiki 1.18, you only need CSS and this code:
{{#css:
#bodyContent { background-color: yellow; }
body {
background: navajowhite;
}
}}
This will give the part of the page with text a yellow colour and the rest (border) a brown-ish colour.
For best results, put this in a template, e.g. {{Page colour}}, so that it can be called with, e.g. {{Page color|red|yellow}}. The template code will then be:
{{#css:
#bodyContent { background-color: {{{1|yellow}}}; }<!-- Page color -->
body {
background: {{{2|navajowhite}}};<!-- Border color -->
}
}}
where 1 & 2 are parameters (page and border respectively) with default colours (yellow and brownish).

Resources