Published
Edited
Aug 13, 2022
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
class Tex {
constructor(plot, text, px, py, options = {}) {
this.plot = plot;
this.px = px;
this.py = py;
this.text = text;
this.options = Object.assign({}, defaults, {
width: 1,
size: 14,
weight: 300,
opacity: 1,
anchor: 'middle',
baseline: 'baseline',
angle: 0,
font: 'sans-serif, verdana, arial',
}, options);
}
round(x){
return Math.round(x*10)/10
}
getPosition() {
const {
x,
y,
} = this.plot;
const px = x(this.px);
const py = y(this.py);
return { px, py };
}
enter(g) {
const {
px,
py,
} = this.getPosition();
const {
stroke,
fill,
opacity,
anchor,
baseline,
weight,
font,
width,
angle,
interactive,
size,
color,
} = this.options;
const round = this.round;
g.append('g')
.attr('class', 'shape')
.attr('fill', color || fill || stroke)
.attr('fill-opacity', opacity)
.attr('stroke-width', width)
.attr('dominant-baseline', baseline)
.style('text-anchor', anchor)
//.style('font-size', size + 'px')
//.style('font-weight', weight)
//.style('font-family', font)
.attr('transform', `translate(${px},${py}) rotate(${angle}) scale(${round(size/16)})`)
.append(() => MJ.tex2svg(this.text).querySelector("svg"));
if (interactive) {
this.createUI(g);
}
}
update(g) {
const {
px,
py,
} = this.getPosition();
const t = this.plot.options.transitions;
const {
stroke,
fill,
opacity,
anchor,
baseline,
weight,
font,
width,
angle,
interactive,
size,
color,
} = this.options;
const round = this.round;
const shape = t ? g.select('.shape').transition() : g.select('.shape');
shape
.attr('fill', color || fill || stroke)
.attr('fill-opacity', opacity)
.attr('stroke-width', width)
.attr('dominant-baseline', baseline)
.style('text-anchor', anchor)
//.style('font-size', size + 'px')
//.style('font-weight', weight)
//.style('font-family', font)
.attr('transform', `translate(${px},${py}) rotate(${angle}) scale(${round(size/16)})`)
.append(() => MJ.tex2svg(this.text).querySelector("svg"));
}
// for interactive points
onChange() {
if (this.options.onChange) {
this.options.onChange({
x: this.px,
y: this.py,
});
}
}
createUI(container) {
const {
x,
y,
} = this.plot;
this.gUI = createUIContainer(container);
this._translate = this.getPosition();
// move handle
const mHandle = addUIHandler(
this,
this.gUI.select('.ghost'),
'move_handle',
() => {
this.px = x.invert(this._translate.px);
this.py = y.invert(this._translate.py);

this.plot.render();
this.onChange();
},
);
}
refreshUI(key, dx, dy) {
const {size}=this.options;
const round = this.round;
const g = this.gUI;
const ghost = g.select('.ghost');
if (key === 'move_handle') {
this._translate.px += dx;
this._translate.py += dy;
} else if (key === 'reset') {
const p = this.getPositions();
this._translate.px = p.px;
this._translate.py = p.py;
}
const { px, py } = this._translate;
ghost.attr('transform', `translate(${px},${py}) scale(${round(size/16)})`);
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
ex0={
// plot functions of x
const p = plotter();
p.func(x => 0.1 * (x ** 3), { stroke: 'green', width: 3 });
p.func(x => (x ** 2) - 6, { stroke: 'orange', width: 3 });
p.func(x => Math.sqrt(x), { stroke: 'purple', width: 3, defined: x => x >= 0 });
p.func(x => -Math.abs(x) - 2, { stroke: 'gray', width: 3, dash: '8,2' });
p.tex(String.raw`\frac{x}{5}`, 1, -6, { size: 24, stroke: 'blue', baseline: 'middle', interactive: true });
return p.node;
}
Insert cell
//https://github.com/mathjax/MathJax/issues/2705#issuecomment-859742446
MJ =
{
if(!window.MathJax){
window.MathJax= {
loader: {load: ['output/svg']},
}
}
/*
else{
window.MathJax={};
}
*/
return await require('https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js')
.catch(() =>{
const MathJax = window.MathJax
const {mathjax} = MathJax._.mathjax;
const {SVG} = MathJax._.output.svg_ts;
//
// Do the normal setup
//
MathJax.startup.defaultReady();
//
// Create an SVG output jax and a new MathDocument that uses it.
//
const svgOutput = new SVG(MathJax.config.svg);
const svgDocument = mathjax.document(document, {
...MathJax.config.options,
InputJax: MathJax.startup.input,
OutputJax: svgOutput
});
//
// Define the SVG-based conversion methods
//
MathJax.tex2svg = (math, options = {}) => {
options.format = svgDocument.inputJax[0].name;
return svgDocument.convert(math, options);
};
MathJax.tex2svgPromise = (math, options = {}) => {
options.format = svgDocument.inputJax[0].name;
return mathjax.handleRetriesFor(() => svgDocument.convert(math, options));
};
MathJax.svgStylesheet = () => svgOutput.styleSheet(svgDocument);
return MathJax
})
}


Insert cell
Insert cell
{
const tex='1\\over 2'
const s = MJ.tex2svg(String.raw`${tex}`)//.querySelector("svg")
return s;
}
// https://observablehq.com/@mcmcclur/d3-graphviz-with-mathjax
Insert cell
window.MathJax
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more