X Cursor Latex implementation
Some checks reported errors
continuous-integration/drone/push Build was killed
Some checks reported errors
continuous-integration/drone/push Build was killed
Also a few bugfixes and added documentation
This commit is contained in:
parent
2691ba687f
commit
166d1a2485
7 changed files with 117 additions and 100 deletions
|
@ -157,7 +157,15 @@ Canvas {
|
|||
*/
|
||||
property int drawMaxX: Math.ceil(Math.max(Math.abs(xmin), Math.abs(px2x(canvasSize.width)))/xaxisstep1)
|
||||
|
||||
/*!
|
||||
\qmlproperty var LogGraphCanvas::imageLoaders
|
||||
Dictionary of format {image: [callback.image data]} containing data for defered image loading.
|
||||
*/
|
||||
property var imageLoaders: {}
|
||||
/*!
|
||||
\qmlproperty var LogGraphCanvas::ctx
|
||||
Cache for the 2D context so that it may be used asynchronously.
|
||||
*/
|
||||
property var ctx
|
||||
|
||||
Component.onCompleted: imageLoaders = {}
|
||||
|
|
|
@ -31,7 +31,7 @@ class Expression {
|
|||
this.calc = C.parser.parse(expr).simplify()
|
||||
this.cached = this.isConstant()
|
||||
this.cachedValue = this.cached ? this.calc.evaluate(C.evalVariables) : null
|
||||
this.latexMarkup = Latex.expressionToLatex(this.calc.tokens)
|
||||
this.latexMarkup = Latex.expression(this.calc.tokens)
|
||||
}
|
||||
|
||||
isConstant() {
|
||||
|
|
|
@ -125,7 +125,7 @@ function variable(vari) {
|
|||
* @param {Array} tokens - expr-eval tokens list
|
||||
* @returns {string}
|
||||
*/
|
||||
function expressionToLatex(tokens) {
|
||||
function expression(tokens) {
|
||||
var nstack = [];
|
||||
var n1, n2, n3;
|
||||
var f, args, argCount;
|
||||
|
@ -239,7 +239,7 @@ function expressionToLatex(tokens) {
|
|||
nstack.push('[' + args.join(', ') + ']');
|
||||
break;
|
||||
case ExprEval.IEXPR:
|
||||
nstack.push('(' + expressionToLatex(item.value) + ')');
|
||||
nstack.push('(' + expression(item.value) + ')');
|
||||
break;
|
||||
case ExprEval.IENDSTATEMENT:
|
||||
break;
|
||||
|
|
|
@ -38,7 +38,7 @@ class Sequence extends Expr.Expression {
|
|||
for(var n in this.calcValues)
|
||||
if(['string', 'number'].includes(typeof this.calcValues[n])) {
|
||||
let parsed = C.parser.parse(this.calcValues[n].toString()).simplify()
|
||||
this.latexValues[n] = Latex.expressionToLatex(parsed.tokens)
|
||||
this.latexValues[n] = Latex.expression(parsed.tokens)
|
||||
this.calcValues[n] = parsed.evaluate(C.evalVariables)
|
||||
}
|
||||
this.valuePlus = parseInt(valuePlus)
|
||||
|
|
|
@ -209,45 +209,12 @@ class DrawableObject {
|
|||
*/
|
||||
draw(canvas, ctx) {}
|
||||
|
||||
|
||||
/**
|
||||
* Automaticly draw the label of the object on the \c canvas with the 2D context \c ctx.
|
||||
* This method takes into account both the \c posX and \c posY of where the label
|
||||
* should be displayed, including the \c labelPosition relative to it.
|
||||
* @param {Canvas} canvas
|
||||
* @param {Context2D} ctx
|
||||
* @param {string|Enum} labelPosition - Position of the label relative to the marked position
|
||||
* @param {number} posX - Component of the marked position on the x-axis
|
||||
* @param {number} posY - Component of the marked position on the y-axis
|
||||
* @param {bool} forceText - Force the rendering of the label as text.
|
||||
*/
|
||||
drawLabel(canvas, ctx, labelPosition, posX, posY, forceText = false) {
|
||||
let offset
|
||||
if(!forceText && true) { // TODO: Check for user setting with Latex.
|
||||
// With latex
|
||||
let drawLblCb = function(canvas, ctx, ltxImg) {
|
||||
this.drawLabelDivergence(labelPosition, 8, ltxImg, posX, posY,
|
||||
(x,y) => canvas.drawVisibleImage(ctx, ltxImg.source, x, y, ltxImg.width, ltxImg.height))
|
||||
}
|
||||
let ltxLabel = this.getLatexLabel();
|
||||
if(ltxLabel != "")
|
||||
canvas.renderLatexImage(ltxLabel, this.color, drawLblCb.bind(this))
|
||||
//canvas.drawVisibleImage(ctx, ltxImg.source, posX, posY)
|
||||
} else {
|
||||
// Without latex
|
||||
let text = this.getLabel()
|
||||
ctx.font = `${canvas.textsize}px sans-serif`
|
||||
this.drawLabelDivergence(labelPosition, 4, canvas.measureText(ctx, text), posX, posY,
|
||||
(x,y) => canvas.drawVisibleText(ctx, text, x, y))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Applicates a \c drawFunction with two position arguments depending on
|
||||
* both the \c posX and \c posY of where the label should be displayed,
|
||||
* and the \c labelPosition which declares the label should be displayed
|
||||
* relatively to that position.
|
||||
*
|
||||
* @param {string|Enum} labelPosition - Position of the label relative to the marked position
|
||||
* @param {number} offset - Margin between the position and the object to be drawn
|
||||
* @param {Dictionary} size - Size of the label item, containing two properties, "width" and "height"
|
||||
|
@ -255,7 +222,7 @@ class DrawableObject {
|
|||
* @param {number} posY - Component of the marked position on the y-axis
|
||||
* @param {function} drawFunction - Function with two arguments (x, y) that will be called to draw the label
|
||||
*/
|
||||
drawLabelDivergence(labelPosition, offset, size, posX, posY, drawFunction) {
|
||||
drawPositionDivergence(labelPosition, offset, size, posX, posY, drawFunction) {
|
||||
switch(labelPosition) {
|
||||
case 'center':
|
||||
drawFunction(posX-size.width/2, posY-size.height/2)
|
||||
|
@ -293,6 +260,56 @@ class DrawableObject {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Automaticly draw text (by default the label of the object on the \c canvas with
|
||||
* the 2D context \c ctx depending on user settings.
|
||||
* This method takes into account both the \c posX and \c posY of where the label
|
||||
* should be displayed, including the \c labelPosition relative to it.
|
||||
* The text is get both through the \c getLatexFunction and \c getTextFunction
|
||||
* depending on whether to use latex.
|
||||
* Then, it's displayed using the \c drawFunctionLatex (x,y,imageData) and
|
||||
* \c drawFunctionText (x,y,text) depending on whether to use latex.
|
||||
*
|
||||
* @param {Canvas} canvas
|
||||
* @param {Context2D} ctx
|
||||
* @param {string|Enum} labelPosition - Position of the label relative to the marked position
|
||||
* @param {number} posX - Component of the marked position on the x-axis
|
||||
* @param {number} posY - Component of the marked position on the y-axis
|
||||
* @param {bool} forceText - Force the rendering of the label as text
|
||||
* @param {function|null} getLatexFunction - Function (no argument) to get the latex markup to be displayed
|
||||
* @param {function|null} getTextFunction - Function (no argument) to get the text to be displayed
|
||||
* @param {function|null} drawFunctionLatex - Function (x,y,imageData) to display the latex image
|
||||
* @param {function|null} drawFunctionText - Function (x,y,text) to display the text
|
||||
*/
|
||||
drawLabel(canvas, ctx, labelPosition, posX, posY, forceText = false,
|
||||
getLatexFunction = null, getTextFunction = null, drawFunctionLatex = null, drawFunctionText = null) {
|
||||
// Default functions
|
||||
if(getLatexFunction == null)
|
||||
getLatexFunction = this.getLatexLabel.bind(this)
|
||||
if(getTextFunction == null)
|
||||
getTextFunction = this.getLabel.bind(this)
|
||||
if(drawFunctionLatex == null)
|
||||
drawFunctionLatex = (x,y,ltxImg) => canvas.drawVisibleImage(ctx, ltxImg.source, x, y, ltxImg.width, ltxImg.height)
|
||||
if(drawFunctionText == null)
|
||||
drawFunctionText = (x,y,text) => canvas.drawVisibleText(ctx, text, x, textSize.height+5)
|
||||
// Drawing the label
|
||||
let offset
|
||||
if(!forceText && true) { // TODO: Check for user setting with Latex.
|
||||
// With latex
|
||||
let drawLblCb = function(canvas, ctx, ltxImg) {
|
||||
this.drawPositionDivergence(labelPosition, 8, ltxImg, posX, posY, (x,y) => drawFunctionLatex(x,y,ltxImg))
|
||||
}
|
||||
let ltxLabel = getLatexFunction();
|
||||
if(ltxLabel != "")
|
||||
canvas.renderLatexImage(ltxLabel, this.color, drawLblCb.bind(this))
|
||||
} else {
|
||||
// Without latex
|
||||
let text = getTextFunction()
|
||||
ctx.font = `${canvas.textsize}px sans-serif`
|
||||
this.drawPositionDivergence(labelPosition, 4, canvas.measureText(ctx, text), posX, posY, (x,y) => drawFunctionText(x,y,text))
|
||||
}
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.name;
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ class Function extends Common.ExecutableObject {
|
|||
return `${Latex.variable(this.name)}:\\begin{array}{llll}${this.definitionDomain.latexMarkup}\\textrm{ } & \\rightarrow & \\textrm{ }${this.destinationDomain.latexMarkup}\\\\
|
||||
x\\textrm{ } & \\mapsto & \\textrm{ }${this.expression.latexMarkup}\\end{array}`
|
||||
} else {
|
||||
return `\\begin{array}{l}${Latex.variable(this.name)}(x) = ${this.expression.latexMarkup}\\\\ textD_{${this.name}} = ${this.definitionDomain.latexMarkup}\\end{array}`
|
||||
return `\\begin{array}{l}${Latex.variable(this.name)}(x) = ${this.expression.latexMarkup}\\\\ D_{${this.name}} = ${this.definitionDomain.latexMarkup}\\end{array}`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,27 +22,14 @@
|
|||
.import "../objects.js" as Objects
|
||||
.import "../mathlib.js" as MathLib
|
||||
.import "../parameters.js" as P
|
||||
.import "../math/latex.js" as Latex
|
||||
|
||||
|
||||
|
||||
class XCursor extends Common.DrawableObject {
|
||||
static type(){return 'X Cursor'}
|
||||
static displayType(){return qsTr('X Cursor')}
|
||||
static displayTypeMultiple(){return qsTr('X Cursors')}
|
||||
/*static properties() {
|
||||
return {
|
||||
'x': 'Expression',
|
||||
'targetElement': new P.ObjectType('ExecutableObject'),
|
||||
'labelPosition': new P.Enum('left', 'right'),
|
||||
'approximate': 'boolean',
|
||||
'rounding': 'number',
|
||||
'displayStyle': new P.Enum(
|
||||
'— — — — — — —',
|
||||
'⸺⸺⸺⸺⸺⸺',
|
||||
'• • • • • • • • • •'
|
||||
),
|
||||
'targetValuePosition' : new P.Enum('Next to target', 'With label', 'Hidden')
|
||||
}
|
||||
}*/
|
||||
static properties() {return {
|
||||
[QT_TRANSLATE_NOOP('prop','x')]: 'Expression',
|
||||
[QT_TRANSLATE_NOOP('prop','targetElement')]: new P.ObjectType('ExecutableObject'),
|
||||
|
@ -87,6 +74,13 @@ class XCursor extends Common.DrawableObject {
|
|||
return `${this.name} = ${this.x.toString()}\n${this.getTargetValueLabel()}`
|
||||
}
|
||||
|
||||
getLatexString() {
|
||||
if(this.targetElement == null) return `${Latex.variable(this.name)} = ${this.x.latexMarkup}`
|
||||
return `\\begin{array}{l}
|
||||
${Latex.variable(this.name)} = ${this.x.latexMarkup} \\\\
|
||||
${this.getTargetValueLatexLabel()}`
|
||||
}
|
||||
|
||||
getTargetValueLabel() {
|
||||
var t = this.targetElement
|
||||
var approx = ''
|
||||
|
@ -98,6 +92,18 @@ class XCursor extends Common.DrawableObject {
|
|||
(this.approximate ? ' ≈ ' + approx : '')
|
||||
}
|
||||
|
||||
getTargetValueLatexLabel() {
|
||||
var t = this.targetElement
|
||||
var approx = ''
|
||||
if(this.approximate) {
|
||||
approx = t.execute(this.x.execute())
|
||||
approx = approx.toPrecision(this.rounding + Math.round(approx).toString().length)
|
||||
}
|
||||
let simpl = t.simplify(this.x.toEditableString())
|
||||
return `${Latex.variable(t.name)}(${Latex.variable(this.name)}) = ${simpl.tokens ? Latex.expression(simpl.tokens) : simpl}` +
|
||||
(this.approximate ? ' \\simeq ' + approx : '')
|
||||
}
|
||||
|
||||
getLabel() {
|
||||
switch(this.labelContent) {
|
||||
case 'name':
|
||||
|
@ -118,8 +124,28 @@ class XCursor extends Common.DrawableObject {
|
|||
}
|
||||
}
|
||||
|
||||
getLatexLabel() {
|
||||
switch(this.labelContent) {
|
||||
case 'name':
|
||||
return Latex.variable(this.name)
|
||||
break;
|
||||
case 'name + value':
|
||||
switch(this.targetValuePosition) {
|
||||
case 'Next to target':
|
||||
case 'Hidden':
|
||||
return `${Latex.variable(this.name)} = ${this.x.latexMarkup}`
|
||||
break;
|
||||
case 'With label':
|
||||
return this.getLatexString()
|
||||
break;
|
||||
}
|
||||
case 'null':
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
draw(canvas, ctx) {
|
||||
var xpos = canvas.x2px(this.x.execute())
|
||||
let xpos = canvas.x2px(this.x.execute())
|
||||
switch(this.displayStyle) {
|
||||
case '— — — — — — —':
|
||||
var dashPxSize = 10
|
||||
|
@ -139,52 +165,18 @@ class XCursor extends Common.DrawableObject {
|
|||
break;
|
||||
}
|
||||
|
||||
// Label
|
||||
var text = this.getLabel()
|
||||
ctx.font = `${canvas.textsize}px sans-serif`
|
||||
var textSize = canvas.measureText(ctx, text)
|
||||
|
||||
switch(this.labelPosition) {
|
||||
case 'left':
|
||||
case 'above-left':
|
||||
case 'below-left':
|
||||
case 'below':
|
||||
case 'above':
|
||||
canvas.drawVisibleText(ctx, text, xpos-textSize.width-5, textSize.height+5)
|
||||
break;
|
||||
case 'right':
|
||||
case 'above-right':
|
||||
case 'below-right':
|
||||
canvas.drawVisibleText(ctx, text, xpos+5, textSize.height+5)
|
||||
break;
|
||||
}
|
||||
// Drawing label at the top of the canvas.
|
||||
this.drawLabel(canvas, ctx, this.labelPosition, xpos, 0, false, null, null,
|
||||
(x,y,ltxImg) => canvas.drawVisibleImage(ctx, ltxImg.source, x, 5, ltxImg.width, ltxImg.height),
|
||||
(x,y,text) => canvas.drawVisibleText(ctx, text, x, textSize.height+5))
|
||||
|
||||
// Drawing label at the position of the target element.
|
||||
if(this.targetValuePosition == 'Next to target' && this.targetElement != null) {
|
||||
var text = this.getTargetValueLabel()
|
||||
var textSize = canvas.measureText(ctx, text)
|
||||
var ypox = canvas.y2px(this.targetElement.execute(this.x.execute()))
|
||||
switch(this.labelPosition) {
|
||||
case 'left':
|
||||
case 'below':
|
||||
case 'above':
|
||||
canvas.drawVisibleText(ctx, text, xpos-textSize.width-5, ypox+textSize.height)
|
||||
break;
|
||||
case 'above-left':
|
||||
canvas.drawVisibleText(ctx, text, xpos-textSize.width-5, ypox+textSize.height+12)
|
||||
break;
|
||||
case 'below-left':
|
||||
canvas.drawVisibleText(ctx, text, xpos-textSize.width-5, ypox+textSize.height-12)
|
||||
break;
|
||||
case 'right':
|
||||
canvas.drawVisibleText(ctx, text, xpos+5, ypox+textSize.height)
|
||||
break;
|
||||
case 'above-right':
|
||||
canvas.drawVisibleText(ctx, text, xpos+5, ypox+textSize.height+12)
|
||||
break;
|
||||
case 'below-right':
|
||||
canvas.drawVisibleText(ctx, text, xpos+5, ypox+textSize.height-12)
|
||||
break;
|
||||
}
|
||||
let ypos = canvas.y2px(this.targetElement.execute(this.x.execute()))
|
||||
this.drawLabel(canvas, ctx, this.labelPosition, xpos, ypos, false,
|
||||
this.getTargetValueLatexLabel.bind(this), this.getTargetValueLabel.bind(this),
|
||||
(x,y,ltxImg) => canvas.drawVisibleImage(ctx, ltxImg.source, x, y, ltxImg.width, ltxImg.height),
|
||||
(x,y,text) => canvas.drawVisibleText(ctx, text, x, y))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue