Reformatting JS files
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Adsooi 2024-09-27 02:54:20 +02:00
parent 8cefc56ac7
commit c32d70e9ed
Signed by: Ad5001
GPG key ID: EF45F9C6AFE20160
45 changed files with 1390 additions and 1326 deletions

View file

@ -538,7 +538,7 @@ Item {
try { try {
expr = new JS.MathLib.Expression(value.toString()) expr = new JS.MathLib.Expression(value.toString())
// Check if the expression is valid, throws error otherwise. // Check if the expression is valid, throws error otherwise.
if(!expr.allRequirementsFullfilled()) { if(!expr.allRequirementsFulfilled()) {
let undefVars = expr.undefinedVariables() let undefVars = expr.undefinedVariables()
if(undefVars.length > 1) if(undefVars.length > 1)
throw new Error(qsTranslate('error', 'No object found with names %1.').arg(undefVars.join(', '))) throw new Error(qsTranslate('error', 'No object found with names %1.').arg(undefVars.join(', ')))

View file

@ -21,10 +21,13 @@ import Objects from "../module/objects.mjs"
export default class ColorChanged extends EditedProperty { export default class ColorChanged extends EditedProperty {
// Action used everytime when an object's color is changed // Action used everytime when an object's color is changed
type(){return 'ColorChanged'} type() {
return "ColorChanged"
icon(){return 'appearance'} }
icon() {
return "appearance"
}
constructor(targetName = "", targetType = "Point", oldColor = "black", newColor = "white") { constructor(targetName = "", targetType = "Point", oldColor = "black", newColor = "white") {
super(targetName, targetType, "color", oldColor, newColor) super(targetName, targetType, "color", oldColor, newColor)
@ -34,7 +37,9 @@ export default class ColorChanged extends EditedProperty {
return [this.targetName, this.targetType, this.previousValue, this.newValue] return [this.targetName, this.targetType, this.previousValue, this.newValue]
} }
color(darkVer=false){return darkVer ? 'purple' : 'plum'} color(darkVer = false) {
return darkVer ? "purple" : "plum"
}
getReadableString() { getReadableString() {
return qsTranslate("color", "%1 %2's color changed from %3 to %4.") return qsTranslate("color", "%1 %2's color changed from %3 to %4.")
@ -49,7 +54,7 @@ export default class ColorChanged extends EditedProperty {
getHTMLString() { getHTMLString() {
return qsTranslate("color", "%1 %2's color changed from %3 to %4.") return qsTranslate("color", "%1 %2's color changed from %3 to %4.")
.arg(Objects.types[this.targetType].displayType()) .arg(Objects.types[this.targetType].displayType())
.arg('<b style="font-size: 15px;">&nbsp;' + this.targetName + "&nbsp;</b>") .arg("<b style=\"font-size: 15px;\">&nbsp;" + this.targetName + "&nbsp;</b>")
.arg(this.formatColor(this.previousValue)).arg(this.formatColor(this.newValue)) .arg(this.formatColor(this.previousValue)).arg(this.formatColor(this.newValue))
} }
} }

View file

@ -25,14 +25,18 @@ export class Action {
* *
* @returns {string} * @returns {string}
*/ */
type(){return 'Unknown'} type() {
return "Unknown"
}
/** /**
* Icon associated with the action. * Icon associated with the action.
* *
* @returns {string} * @returns {string}
*/ */
icon(){return 'position'} icon() {
return "position"
}
// TargetName is the name of the object that's targeted by the event. // TargetName is the name of the object that's targeted by the event.
constructor(targetName = "", targetType = "Point") { constructor(targetName = "", targetType = "Point") {
@ -43,12 +47,14 @@ export class Action {
/** /**
* Undoes the action. * Undoes the action.
*/ */
undo() {} undo() {
}
/** /**
* Redoes the action. * Redoes the action.
*/ */
redo() {} redo() {
}
/** /**
* Export the action to a serializable format. * Export the action to a serializable format.
@ -61,12 +67,12 @@ export class Action {
} }
/** /**
* Returns a string with the human readable description of the action. * Returns a string with the human-readable description of the action.
* *
* @returns {string} * @returns {string}
*/ */
getReadableString() { getReadableString() {
return 'Unknown action' return "Unknown action"
} }
/** /**
@ -76,7 +82,7 @@ export class Action {
* @returns {string} * @returns {string}
*/ */
getIconRichText(type) { getIconRichText(type) {
return `<img source="../icons/objects/${type}.svg" style="color: ${History.themeTextColor};" width=18 height=18></img>` return `<img src="../icons/objects/${type}.svg" style="color: ${History.themeTextColor};" width=18 height=18></img>`
} }
/** /**
@ -94,7 +100,7 @@ export class Action {
imgDepth * (History.fontSize + 2), imgDepth * (History.fontSize + 2),
History.themeTextColor History.themeTextColor
) )
return `<img src="${source}" width="${width/imgDepth}" height="${height/imgDepth}" style="vertical-align: middle"/>` return `<img src="${source}" width="${width / imgDepth}" height="${height / imgDepth}" style="vertical-align: middle"/>`
} }
/** /**

View file

@ -19,13 +19,21 @@
import Objects from "../module/objects.mjs" import Objects from "../module/objects.mjs"
import { Action } from "./common.mjs" import { Action } from "./common.mjs"
/**
* Action used for the creation of an object.
*/
export default class CreateNewObject extends Action { export default class CreateNewObject extends Action {
// Action used for the creation of an object type() {
type(){return 'CreateNewObject'} return "CreateNewObject"
}
icon(){return 'create'} icon() {
return "create"
}
color(darkVer=false){return darkVer ? 'green' : 'lime'} color(darkVer = false) {
return darkVer ? "green" : "lime"
}
constructor(targetName = "", targetType = "Point", properties = []) { constructor(targetName = "", targetType = "Point", properties = []) {
super(targetName, targetType) super(targetName, targetType)
@ -55,7 +63,7 @@ export default class CreateNewObject extends Action {
getHTMLString() { getHTMLString() {
return qsTranslate("create", "New %1 %2 created.") return qsTranslate("create", "New %1 %2 created.")
.arg(Objects.types[this.targetType].displayType()) .arg(Objects.types[this.targetType].displayType())
.arg('<b style="font-size: 15px;">' + this.targetName + "</b>") .arg("<b style=\"font-size: 15px;\">" + this.targetName + "</b>")
} }
} }

View file

@ -20,10 +20,10 @@ import Objects from "../module/objects.mjs"
import CreateNewObject from "./create.mjs" import CreateNewObject from "./create.mjs"
export default class DeleteObject extends CreateNewObject { /**
/**
* Action used at the deletion of an object. Basically the same thing as creating a new object, except Redo & Undo are reversed. * Action used at the deletion of an object. Basically the same thing as creating a new object, except Redo & Undo are reversed.
*/ */
export default class DeleteObject extends CreateNewObject {
type(){return 'DeleteObject'} type(){return 'DeleteObject'}
icon(){return 'delete'} icon(){return 'delete'}

View file

@ -22,14 +22,20 @@ import * as MathLib from "../math/index.mjs"
import { Action } from "./common.mjs" import { Action } from "./common.mjs"
import { DrawableObject } from "../objs/common.mjs" import { DrawableObject } from "../objs/common.mjs"
/**
* Action used everytime an object's property has been changed.
*/
export default class EditedProperty extends Action { export default class EditedProperty extends Action {
// Action used everytime an object's property has been changed type() {
type(){return 'EditedProperty'} return "EditedProperty"
}
icon(){return 'modify'} icon() {
return "modify"
}
color(darkVer=false){ color(darkVer = false) {
return darkVer ? 'darkslateblue' : 'cyan'; return darkVer ? "darkslateblue" : "cyan"
} }
/** /**
@ -49,12 +55,12 @@ export default class EditedProperty extends Action {
this.newValue = newValue this.newValue = newValue
this.propertyType = Objects.types[targetType].properties()[targetProperty] this.propertyType = Objects.types[targetType].properties()[targetProperty]
if(valueIsExpressionNeedingImport) { if(valueIsExpressionNeedingImport) {
if(typeof this.propertyType == 'object' && this.propertyType.type === "Expression") { if(typeof this.propertyType == "object" && this.propertyType.type === "Expression") {
this.previousValue = new MathLib.Expression(this.previousValue); this.previousValue = new MathLib.Expression(this.previousValue)
this.newValue = new MathLib.Expression(this.newValue); this.newValue = new MathLib.Expression(this.newValue)
} else if(this.propertyType === "Domain") { } else if(this.propertyType === "Domain") {
this.previousValue = MathLib.parseDomain(this.previousValue); this.previousValue = MathLib.parseDomain(this.previousValue)
this.newValue = MathLib.parseDomain(this.newValue); this.newValue = MathLib.parseDomain(this.newValue)
} else { } else {
// Objects // Objects
this.previousValue = Objects.currentObjectsByName[this.previousValue] // Objects.getObjectByName(this.previousValue); this.previousValue = Objects.currentObjectsByName[this.previousValue] // Objects.getObjectByName(this.previousValue);
@ -93,42 +99,42 @@ export default class EditedProperty extends Action {
case "Enum": case "Enum":
this.prevString = this.propertyType.translatedValues[this.propertyType.values.indexOf(this.previousValue)] this.prevString = this.propertyType.translatedValues[this.propertyType.values.indexOf(this.previousValue)]
this.nextString = this.propertyType.translatedValues[this.propertyType.values.indexOf(this.newValue)] this.nextString = this.propertyType.translatedValues[this.propertyType.values.indexOf(this.newValue)]
break; break
case "ObjectType": case "ObjectType":
this.prevString = this.previousValue == null ? "null" : this.previousValue.name this.prevString = this.previousValue == null ? "null" : this.previousValue.name
this.nextString = this.newValue == null ? "null" : this.newValue.name this.nextString = this.newValue == null ? "null" : this.newValue.name
break; break
case "List": case "List":
this.prevString = this.previousValue.join(",") this.prevString = this.previousValue.join(",")
this.nextString = this.newValue.name.join(",") this.nextString = this.newValue.name.join(",")
break; break
case "Dict": case "Dict":
this.prevString = JSON.stringify(this.previousValue) this.prevString = JSON.stringify(this.previousValue)
this.nextString = JSON.stringify(this.newValue) this.nextString = JSON.stringify(this.newValue)
break; break
case "Expression": case "Expression":
this.prevString = this.previousValue == null ? "null" : this.previousValue.toString() this.prevString = this.previousValue == null ? "null" : this.previousValue.toString()
this.nextString = this.newValue == null ? "null" : this.newValue.toString() this.nextString = this.newValue == null ? "null" : this.newValue.toString()
break; break
} }
} else { } else {
this.prevString = this.previousValue == null ? "null" : this.previousValue.toString() this.prevString = this.previousValue == null ? "null" : this.previousValue.toString()
this.nextString = this.newValue == null ? "null" : this.newValue.toString() this.nextString = this.newValue == null ? "null" : this.newValue.toString()
} }
// HTML // HTML
this.prevHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+this.prevString+'&nbsp;</tt>' this.prevHTML = "<tt style=\"background: rgba(128,128,128,0.1);\">&nbsp;" + this.prevString + "&nbsp;</tt>"
this.nextHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+this.nextString+'&nbsp;</tt>' this.nextHTML = "<tt style=\"background: rgba(128,128,128,0.1);\">&nbsp;" + this.nextString + "&nbsp;</tt>"
if(Latex.enabled && typeof this.propertyType == 'object' && this.propertyType.type === "Expression") { if(Latex.enabled && typeof this.propertyType == "object" && this.propertyType.type === "Expression") {
// Store promises so that querying can wait for them to finish. // Store promises so that querying can wait for them to finish.
this._renderPromises = [ this._renderPromises = [
this.renderLatexAsHtml(this.previousValue.latexMarkup).then(prev => this.prevHTML = prev), this.renderLatexAsHtml(this.previousValue.latexMarkup).then(prev => this.prevHTML = prev),
this.renderLatexAsHtml(this.newValue.latexMarkup).then(next => this.nextHTML = prev) this.renderLatexAsHtml(this.newValue.latexMarkup).then(next => this.nextHTML = next)
] ]
} }
} }
getReadableString() { getReadableString() {
return qsTranslate("editproperty", '%1 of %2 %3 changed from "%4" to "%5".') return qsTranslate("editproperty", "%1 of %2 %3 changed from \"%4\" to \"%5\".")
.arg(this.targetPropertyReadable) .arg(this.targetPropertyReadable)
.arg(Objects.types[this.targetType].displayType()) .arg(Objects.types[this.targetType].displayType())
.arg(this.targetName).arg(this.prevString).arg(this.nextString) .arg(this.targetName).arg(this.prevString).arg(this.nextString)
@ -139,9 +145,9 @@ export default class EditedProperty extends Action {
* @return {Promise<string>|string} * @return {Promise<string>|string}
*/ */
async getHTMLString() { async getHTMLString() {
const translation = qsTranslate("editproperty", '%1 of %2 changed from %3 to %4.') const translation = qsTranslate("editproperty", "%1 of %2 changed from %3 to %4.")
.arg(this.targetPropertyReadable) .arg(this.targetPropertyReadable)
.arg('<b style="font-size: 15px;">&nbsp;' + this.targetName + '&nbsp;</b>') .arg("<b style=\"font-size: 15px;\">&nbsp;" + this.targetName + "&nbsp;</b>")
// Check if we need to wait for LaTeX HTML to be rendered. // Check if we need to wait for LaTeX HTML to be rendered.
if(this.prevHTML === undefined || this.nextHTML === undefined) { if(this.prevHTML === undefined || this.nextHTML === undefined) {
const [prevHTML, nextHTML] = await Promise.all(this._renderPromises) const [prevHTML, nextHTML] = await Promise.all(this._renderPromises)

View file

@ -19,9 +19,10 @@
import EditedProperty from "./editproperty.mjs" import EditedProperty from "./editproperty.mjs"
import Objects from "../module/objects.mjs" import Objects from "../module/objects.mjs"
/**
* Action used everytime an object's name has been changed.
*/
export default class NameChanged extends EditedProperty { export default class NameChanged extends EditedProperty {
// Action used everytime an object's property has been changed
type(){return 'NameChanged'} type(){return 'NameChanged'}
icon(){return 'name'} icon(){return 'name'}

View file

@ -21,28 +21,33 @@ import Latex from "../module/latex.mjs"
import * as MathLib from "../math/index.mjs" import * as MathLib from "../math/index.mjs"
import { escapeHTML } from "../utils.mjs" import { escapeHTML } from "../utils.mjs"
import { Action } from "./common.mjs" import { Action } from "./common.mjs"
import { DrawableObject } from "../objs/common.mjs"
/**
* Action used for objects that have a X and Y expression properties (points, texts...)
*/
export default class EditedPosition extends Action { export default class EditedPosition extends Action {
// Action used for objects that have a X and Y expression properties (points, texts...) type() {
type(){return 'EditedPosition'} return "EditedPosition"
}
icon(){return 'position'} icon() {
return "position"
}
color(darkVer=false){ color(darkVer = false) {
return darkVer ? 'seagreen' : 'lightseagreen'; return darkVer ? "seagreen" : "lightseagreen"
} }
constructor(targetName = "", targetType = "Point", previousXValue = "", newXValue = "", previousYValue = "", newYValue = "") { constructor(targetName = "", targetType = "Point", previousXValue = "", newXValue = "", previousYValue = "", newYValue = "") {
super(targetName, targetType) super(targetName, targetType)
let imports = { let imports = {
'previousXValue': previousXValue, "previousXValue": previousXValue,
'previousYValue': previousYValue, "previousYValue": previousYValue,
'newXValue': newXValue, "newXValue": newXValue,
'newYValue': newYValue "newYValue": newYValue
} }
for(let name in imports) for(let name in imports)
this[name] = (typeof imports[name]) == 'string' ? new MathLib.Expression(imports[name]) : imports[name] this[name] = (typeof imports[name]) == "string" ? new MathLib.Expression(imports[name]) : imports[name]
this.setReadableValues() this.setReadableValues()
} }
@ -71,8 +76,8 @@ export default class EditedPosition extends Action {
this.renderLatexAsHtml(nextMarkup) this.renderLatexAsHtml(nextMarkup)
] ]
} else { } else {
this.prevHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+escapeHTML(this.prevString)+'&nbsp;</tt>' this.prevHTML = "<tt style=\"background: rgba(128,128,128,0.1);\">&nbsp;" + escapeHTML(this.prevString) + "&nbsp;</tt>"
this.nextHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+escapeHTML(this.nextString)+'&nbsp;</tt>' this.nextHTML = "<tt style=\"background: rgba(128,128,128,0.1);\">&nbsp;" + escapeHTML(this.nextString) + "&nbsp;</tt>"
} }
} }
@ -84,14 +89,14 @@ export default class EditedPosition extends Action {
} }
getReadableString() { getReadableString() {
return qsTranslate("position", 'Position of %1 %2 set from "%3" to "%4".') return qsTranslate("position", "Position of %1 %2 set from \"%3\" to \"%4\".")
.arg(Objects.types[this.targetType].displayType()) .arg(Objects.types[this.targetType].displayType())
.arg(this.targetName).arg(this.prevString).arg(this.nextString) .arg(this.targetName).arg(this.prevString).arg(this.nextString)
} }
async getHTMLString() { async getHTMLString() {
const translation = qsTranslate("position", 'Position of %1 set from %2 to %3.') const translation = qsTranslate("position", "Position of %1 set from %2 to %3.")
.arg('<b style="font-size: 15px;">&nbsp;' + this.targetName + '&nbsp;</b>') .arg("<b style=\"font-size: 15px;\">&nbsp;" + this.targetName + "&nbsp;</b>")
// Check if we need to wait for LaTeX HTML to be rendered. // Check if we need to wait for LaTeX HTML to be rendered.
if(this.prevHTML === undefined || this.nextHTML === undefined) { if(this.prevHTML === undefined || this.nextHTML === undefined) {
const [prevHTML, nextHTML] = await Promise.all(this._renderPromises) const [prevHTML, nextHTML] = await Promise.all(this._renderPromises)

View file

@ -20,16 +20,22 @@ import EditedProperty from "./editproperty.mjs"
import Objects from "../module/objects.mjs" import Objects from "../module/objects.mjs"
/**
* Action used when an object's shown or hidden.
*/
export default class EditedVisibility extends EditedProperty { export default class EditedVisibility extends EditedProperty {
// Action used when an object's shown or hidden. type() {
type(){return 'EditedVisibility'} return "EditedVisibility"
}
icon(){return 'visibility'} icon() {
return "visibility"
}
color(darkVer=false){ color(darkVer = false) {
return this.newValue ? return this.newValue ?
(darkVer ? 'darkgray' : 'whitesmoke') : (darkVer ? "darkgray" : "whitesmoke") :
(darkVer ? 'dimgray' : 'lightgray') (darkVer ? "dimgray" : "lightgray")
} }
constructor(targetName = "", targetType = "Point", newValue = true) { constructor(targetName = "", targetType = "Point", newValue = true) {
@ -41,15 +47,15 @@ export default class EditedVisibility extends EditedProperty {
} }
getReadableString() { getReadableString() {
return (this.newValue ? qsTranslate('visibility', '%1 %2 shown.') : qsTranslate('visibility', '%1 %2 hidden.')) return (this.newValue ? qsTranslate("visibility", "%1 %2 shown.") : qsTranslate("visibility", "%1 %2 hidden."))
.arg(Objects.types[this.targetType].displayType()) .arg(Objects.types[this.targetType].displayType())
.arg(this.targetName) .arg(this.targetName)
} }
getHTMLString() { getHTMLString() {
return (this.newValue ? qsTranslate('visibility', '%1 %2 shown.') : qsTranslate('visibility', '%1 %2 hidden.')) return (this.newValue ? qsTranslate("visibility", "%1 %2 shown.") : qsTranslate("visibility", "%1 %2 hidden."))
.arg(Objects.types[this.targetType].displayType()) .arg(Objects.types[this.targetType].displayType())
.arg('<b style="font-size: 15px;">' + this.targetName + "</b>") .arg("<b style=\"font-size: 15px;\">" + this.targetName + "</b>")
} }
} }

View file

@ -23,34 +23,43 @@ import { Expression, executeExpression } from "./expression.mjs"
* It doesn't represent any kind of domain and is meant to be extended. * It doesn't represent any kind of domain and is meant to be extended.
*/ */
export class Domain { export class Domain {
constructor() {} constructor() {
}
/** /**
* Checks whether x is included in the domain. * Checks whether x is included in the domain.
* @param {number} x - The x value. * @param {number} x - The x value.
* @return {boolean} true if included, false otherwise. * @return {boolean} true if included, false otherwise.
*/ */
includes(x) { return false } includes(x) {
return false
}
/** /**
* Returns a string representation of the domain. * Returns a string representation of the domain.
* @return {string} String representation of the domain. * @return {string} String representation of the domain.
*/ */
toString() { return '???' } toString() {
return "???"
}
/** /**
* Returns a new domain that is the union between this domain and another. * Returns a new domain that is the union between this domain and another.
* @param {Domain} domain - Domain to unionise with this. * @param {Domain} domain - Domain to unionise with this.
* @return {Domain} newly created domain. * @return {Domain} newly created domain.
*/ */
union(domain) { return domain } union(domain) {
return domain
}
/** /**
* Returns a new domain that is the intersection between this domain and another. * Returns a new domain that is the intersection between this domain and another.
* @param {Domain} domain - Domain to get the interscection with this. * @param {Domain} domain - Domain to get the interscection with this.
* @return {Domain} newly created domain. * @return {Domain} newly created domain.
*/ */
intersection(domain) { return this } intersection(domain) {
return this
}
/** /**
* Imports a domain from a string. * Imports a domain from a string.
@ -61,24 +70,20 @@ export class Domain {
case "R": case "R":
case "": case "":
return Domain.R return Domain.R
break;
case "RE": case "RE":
case "R*": case "R*":
case "*": case "*":
return Domain.RE return Domain.RE
break;
case "RP": case "RP":
case "R+": case "R+":
case "ℝ⁺": case "ℝ⁺":
case "+": case "+":
return Domain.RP return Domain.RP
break;
case "RM": case "RM":
case "R-": case "R-":
case "ℝ⁻": case "ℝ⁻":
case "-": case "-":
return Domain.RM return Domain.RM
break;
case "RPE": case "RPE":
case "REP": case "REP":
case "R+*": case "R+*":
@ -88,7 +93,6 @@ export class Domain {
case "*+": case "*+":
case "+*": case "+*":
return Domain.RPE return Domain.RPE
break;
case "RME": case "RME":
case "REM": case "REM":
case "R-*": case "R-*":
@ -98,7 +102,6 @@ export class Domain {
case "-*": case "-*":
case "*-": case "*-":
return Domain.RME return Domain.RME
break;
case "": case "":
case "N": case "N":
case "ZP": case "ZP":
@ -106,12 +109,10 @@ export class Domain {
case "ℤ⁺": case "ℤ⁺":
case "+": case "+":
return Domain.N return Domain.N
break;
case "NLOG": case "NLOG":
case "ℕˡᵒᵍ": case "ℕˡᵒᵍ":
case "LOG": case "LOG":
return Domain.NLog return Domain.NLog
break;
case "NE": case "NE":
case "NP": case "NP":
case "N*": case "N*":
@ -128,17 +129,14 @@ export class Domain {
case "+*": case "+*":
case "*+": case "*+":
return Domain.NE return Domain.NE
break;
case "Z": case "Z":
case "": case "":
return Domain.Z return Domain.Z
break;
case "ZM": case "ZM":
case "Z-": case "Z-":
case "ℤ⁻": case "ℤ⁻":
case "-": case "-":
return Domain.ZM return Domain.ZM
break;
case "ZME": case "ZME":
case "ZEM": case "ZEM":
case "Z-*": case "Z-*":
@ -148,15 +146,12 @@ export class Domain {
case "-*": case "-*":
case "*-": case "*-":
return Domain.ZME return Domain.ZME
break;
case "ZE": case "ZE":
case "Z*": case "Z*":
case "*": case "*":
return Domain.ZE return Domain.ZE
break;
default: default:
return Domain.EmptySet return Domain.EmptySet
break;
} }
} }
} }
@ -171,15 +166,25 @@ export class EmptySet extends Domain {
this.latexMarkup = "\\emptyset" this.latexMarkup = "\\emptyset"
} }
includes(x) { return false } includes(x) {
return false
}
toString() { return this.displayName } toString() {
return this.displayName
}
union(domain) { return domain } union(domain) {
return domain
}
intersection(domain) { return this } intersection(domain) {
return this
}
static import(frm) { return new EmptySet() } static import(frm) {
return new EmptySet()
}
} }
Domain.EmptySet = new EmptySet() // To prevent use prior to declaration. Domain.EmptySet = new EmptySet() // To prevent use prior to declaration.
@ -190,9 +195,9 @@ Domain.EmptySet = new EmptySet() // To prevent use prior to declaration.
export class Range extends Domain { export class Range extends Domain {
constructor(begin, end, openBegin, openEnd) { constructor(begin, end, openBegin, openEnd) {
super() super()
if(typeof begin == 'number' || typeof begin == 'string') begin = new Expression(begin.toString()) if(typeof begin == "number" || typeof begin == "string") begin = new Expression(begin.toString())
this.begin = begin this.begin = begin
if(typeof end == 'number' || typeof end == 'string') end = new Expression(end.toString()) if(typeof end == "number" || typeof end == "string") end = new Expression(end.toString())
this.end = end this.end = end
this.openBegin = openBegin this.openBegin = openBegin
this.openEnd = openEnd this.openEnd = openEnd
@ -202,7 +207,7 @@ export class Range extends Domain {
includes(x) { includes(x) {
if(x instanceof Expression) x = x.execute() if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == "string") x = executeExpression(x)
return ((this.openBegin && x > this.begin.execute()) || (!this.openBegin && x >= this.begin.execute())) && return ((this.openBegin && x > this.begin.execute()) || (!this.openBegin && x >= this.begin.execute())) &&
((this.openEnd && x < this.end.execute()) || (!this.openEnd && x <= this.end.execute())) ((this.openEnd && x < this.end.execute()) || (!this.openEnd && x <= this.end.execute()))
} }
@ -231,8 +236,8 @@ export class Range extends Domain {
static import(frm) { static import(frm) {
let openBegin = frm.trim().charAt(0) === "]" let openBegin = frm.trim().charAt(0) === "]"
let openEnd = frm.trim().charAt(frm.length -1) === "[" let openEnd = frm.trim().charAt(frm.length - 1) === "["
let [begin, end] = frm.substr(1, frm.length-2).split(";") let [begin, end] = frm.substring(1, frm.length - 1).split(";")
return new Range(begin.trim(), end.trim(), openBegin, openEnd) return new Range(begin.trim(), end.trim(), openBegin, openEnd)
} }
} }
@ -261,19 +266,19 @@ export class SpecialDomain extends Domain {
includes(x) { includes(x) {
if(x instanceof Expression) x = x.execute() if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == "string") x = executeExpression(x)
return this.isValid(x) return this.isValid(x)
} }
next(x) { next(x) {
if(x instanceof Expression) x = x.execute() if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == "string") x = executeExpression(x)
return this.nextValue(x) return this.nextValue(x)
} }
previous(x) { previous(x) {
if(x instanceof Expression) x = x.execute() if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == "string") x = executeExpression(x)
return this.prevValue(x) return this.prevValue(x)
} }
@ -305,7 +310,7 @@ export class SpecialDomain extends Domain {
*/ */
export class DomainSet extends SpecialDomain { export class DomainSet extends SpecialDomain {
constructor(values) { constructor(values) {
super('', x => true, x => x, true) super("", () => true, x => x, true)
let newVals = {} let newVals = {}
this.executedValues = [] this.executedValues = []
for(let value of values) { for(let value of values) {
@ -314,7 +319,7 @@ export class DomainSet extends SpecialDomain {
newVals[ex] = expr newVals[ex] = expr
this.executedValues.push(ex) this.executedValues.push(ex)
} }
this.executedValues.sort((a,b) => a-b) this.executedValues.sort((a, b) => a - b)
this.values = this.executedValues.map(val => newVals[val]) this.values = this.executedValues.map(val => newVals[val])
this.displayName = "{" + this.values.join(";") + "}" this.displayName = "{" + this.values.join(";") + "}"
this.latexMarkup = `\\{${this.values.join(";")}\\}` this.latexMarkup = `\\{${this.values.join(";")}\\}`
@ -322,7 +327,7 @@ export class DomainSet extends SpecialDomain {
includes(x) { includes(x) {
if(x instanceof Expression) x = x.execute() if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == "string") x = executeExpression(x)
for(let value of this.values) for(let value of this.values)
if(x === value.execute()) return true if(x === value.execute()) return true
return false return false
@ -330,10 +335,10 @@ export class DomainSet extends SpecialDomain {
next(x) { next(x) {
if(x instanceof Expression) x = x.execute() if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == "string") x = executeExpression(x)
if(x < this.executedValues[0]) return this.executedValues[0] if(x < this.executedValues[0]) return this.executedValues[0]
for(let i = 1; i < this.values.length; i++) { for(let i = 1; i < this.values.length; i++) {
let prevValue = this.executedValues[i-1] let prevValue = this.executedValues[i - 1]
let value = this.executedValues[i] let value = this.executedValues[i]
if(x >= prevValue && x < value) return value if(x >= prevValue && x < value) return value
} }
@ -342,11 +347,11 @@ export class DomainSet extends SpecialDomain {
previous(x) { previous(x) {
if(x instanceof Expression) x = x.execute() if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == "string") x = executeExpression(x)
if(x > this.executedValues[this.executedValues.length-1]) if(x > this.executedValues[this.executedValues.length - 1])
return this.executedValues[this.executedValues.length-1] return this.executedValues[this.executedValues.length - 1]
for(let i = 1; i < this.values.length; i++) { for(let i = 1; i < this.values.length; i++) {
let prevValue = this.executedValues[i-1] let prevValue = this.executedValues[i - 1]
let value = this.executedValues[i] let value = this.executedValues[i]
if(x > prevValue && x <= value) return prevValue if(x > prevValue && x <= value) return prevValue
} }
@ -361,7 +366,7 @@ export class DomainSet extends SpecialDomain {
if(domain instanceof EmptySet) return this if(domain instanceof EmptySet) return this
if(domain instanceof DomainSet) { if(domain instanceof DomainSet) {
let newValues = [] let newValues = []
let values = this.values.concat(domain.values).filter(function(val){ let values = this.values.concat(domain.values).filter(function(val) {
newValues.push(val.execute()) newValues.push(val.execute())
return newValues.indexOf(val.execute()) === newValues.length - 1 return newValues.indexOf(val.execute()) === newValues.length - 1
}) })
@ -389,7 +394,7 @@ export class DomainSet extends SpecialDomain {
if(domain instanceof EmptySet) return domain if(domain instanceof EmptySet) return domain
if(domain instanceof DomainSet) { if(domain instanceof DomainSet) {
let domValues = domain.values.map(expr => expr.execute()) let domValues = domain.values.map(expr => expr.execute())
this.values = this.values.filter(function(val){ this.values = this.values.filter(function(val) {
return domValues.indexOf(val.execute()) >= 0 return domValues.indexOf(val.execute()) >= 0
}) })
return this return this
@ -414,7 +419,7 @@ export class DomainSet extends SpecialDomain {
} }
static import(frm) { static import(frm) {
return new DomainSet(frm.substr(1, frm.length-2).split(";")) return new DomainSet(frm.substring(1, frm.length - 1).split(";"))
} }
} }
@ -459,7 +464,7 @@ export class UnionDomain extends Domain {
let domains = frm.trim().split("") let domains = frm.trim().split("")
if(domains.length === 1) domains = frm.trim().split("U") // Fallback if(domains.length === 1) domains = frm.trim().split("U") // Fallback
let dom2 = parseDomain(domains.pop()) let dom2 = parseDomain(domains.pop())
let dom1 = parseDomain(domains.join('')) let dom1 = parseDomain(domains.join(""))
return dom1.union(dom2) return dom1.union(dom2)
} }
} }
@ -504,7 +509,7 @@ export class IntersectionDomain extends Domain {
static import(frm) { static import(frm) {
let domains = frm.trim().split("∩") let domains = frm.trim().split("∩")
let dom1 = parseDomain(domains.pop()) let dom1 = parseDomain(domains.pop())
let dom2 = parseDomain(domains.join('∩')) let dom2 = parseDomain(domains.join("∩"))
return dom1.intersection(dom2) return dom1.intersection(dom2)
} }
} }
@ -533,7 +538,7 @@ export class MinusDomain extends Domain {
let domains = frm.trim().split("") let domains = frm.trim().split("")
if(domains.length === 1) domains = frm.trim().split("\\") // Fallback if(domains.length === 1) domains = frm.trim().split("\\") // Fallback
let dom1 = parseDomain(domains.shift()) let dom1 = parseDomain(domains.shift())
let dom2 = parseDomain(domains.join('')) let dom2 = parseDomain(domains.join(""))
return new MinusDomain(dom1, dom2) return new MinusDomain(dom1, dom2)
} }
} }
@ -542,52 +547,52 @@ Domain.RE = new MinusDomain("R", "{0}")
Domain.RE.displayName = "*" Domain.RE.displayName = "*"
Domain.RE.latexMarkup = "\\mathbb{R}^{*}" Domain.RE.latexMarkup = "\\mathbb{R}^{*}"
Domain.R = new Range(-Infinity,Infinity,true,true) Domain.R = new Range(-Infinity, Infinity, true, true)
Domain.R.displayName = "" Domain.R.displayName = ""
Domain.R.latexMarkup = "\\mathbb{R}" Domain.R.latexMarkup = "\\mathbb{R}"
Domain.RP = new Range(0,Infinity,true,false) Domain.RP = new Range(0, Infinity, true, false)
Domain.RP.displayName = "ℝ⁺" Domain.RP.displayName = "ℝ⁺"
Domain.RP.latexMarkup = "\\mathbb{R}^{+}" Domain.RP.latexMarkup = "\\mathbb{R}^{+}"
Domain.RM = new Range(-Infinity,0,true,false) Domain.RM = new Range(-Infinity, 0, true, false)
Domain.RM.displayName = "ℝ⁻" Domain.RM.displayName = "ℝ⁻"
Domain.RM.latexMarkup = "\\mathbb{R}^{-}" Domain.RM.latexMarkup = "\\mathbb{R}^{-}"
Domain.RPE = new Range(0,Infinity,true,true) Domain.RPE = new Range(0, Infinity, true, true)
Domain.RPE.displayName = "ℝ⁺*" Domain.RPE.displayName = "ℝ⁺*"
Domain.RPE.latexMarkup = "\\mathbb{R}^{+*}" Domain.RPE.latexMarkup = "\\mathbb{R}^{+*}"
Domain.RME = new Range(-Infinity,0,true,true) Domain.RME = new Range(-Infinity, 0, true, true)
Domain.RME.displayName = "ℝ⁻*" Domain.RME.displayName = "ℝ⁻*"
Domain.RME.latexMarkup = "\\mathbb{R}^{+*}" Domain.RME.latexMarkup = "\\mathbb{R}^{+*}"
Domain.N = new SpecialDomain('', x => x%1===0 && x >= 0, Domain.N = new SpecialDomain("", x => x % 1 === 0 && x >= 0,
x => Math.max(Math.floor(x)+1, 0), x => Math.max(Math.floor(x) + 1, 0),
x => Math.max(Math.ceil(x)-1, 0)) x => Math.max(Math.ceil(x) - 1, 0))
Domain.N.latexMarkup = "\\mathbb{N}" Domain.N.latexMarkup = "\\mathbb{N}"
Domain.NE = new SpecialDomain('*', x => x%1===0 && x > 0, Domain.NE = new SpecialDomain("*", x => x % 1 === 0 && x > 0,
x => Math.max(Math.floor(x)+1, 1), x => Math.max(Math.floor(x) + 1, 1),
x => Math.max(Math.ceil(x)-1, 1)) x => Math.max(Math.ceil(x) - 1, 1))
Domain.NE.latexMarkup = "\\mathbb{N}^{*}" Domain.NE.latexMarkup = "\\mathbb{N}^{*}"
Domain.Z = new SpecialDomain('', x => x%1===0, x => Math.floor(x)+1, x => Math.ceil(x)-1) Domain.Z = new SpecialDomain("", x => x % 1 === 0, x => Math.floor(x) + 1, x => Math.ceil(x) - 1)
Domain.Z.latexMarkup = "\\mathbb{Z}" Domain.Z.latexMarkup = "\\mathbb{Z}"
Domain.ZE = new SpecialDomain('*', x => x%1===0 && x !== 0, Domain.ZE = new SpecialDomain("*", x => x % 1 === 0 && x !== 0,
x => Math.floor(x)+1 === 0 ? Math.floor(x)+2 : Math.floor(x)+1, x => Math.floor(x) + 1 === 0 ? Math.floor(x) + 2 : Math.floor(x) + 1,
x => Math.ceil(x)-1 === 0 ? Math.ceil(x)-2 : Math.ceil(x)-1) x => Math.ceil(x) - 1 === 0 ? Math.ceil(x) - 2 : Math.ceil(x) - 1)
Domain.ZE.latexMarkup = "\\mathbb{Z}^{*}" Domain.ZE.latexMarkup = "\\mathbb{Z}^{*}"
Domain.ZM = new SpecialDomain('ℤ⁻', x => x%1===0 && x <= 0, Domain.ZM = new SpecialDomain("ℤ⁻", x => x % 1 === 0 && x <= 0,
x => Math.min(Math.floor(x)+1, 0), x => Math.min(Math.floor(x) + 1, 0),
x => Math.min(Math.ceil(x)-1, 0)) x => Math.min(Math.ceil(x) - 1, 0))
Domain.ZM.latexMarkup = "\\mathbb{Z}^{-}" Domain.ZM.latexMarkup = "\\mathbb{Z}^{-}"
Domain.ZME = new SpecialDomain('ℤ⁻*', x => x%1===0 && x < 0, Domain.ZME = new SpecialDomain("ℤ⁻*", x => x % 1 === 0 && x < 0,
x => Math.min(Math.floor(x)+1, -1), x => Math.min(Math.floor(x) + 1, -1),
x => Math.min(Math.ceil(x)-1, -1)) x => Math.min(Math.ceil(x) - 1, -1))
Domain.ZME.latexMarkup = "\\mathbb{Z}^{-*}" Domain.ZME.latexMarkup = "\\mathbb{Z}^{-*}"
Domain.NLog = new SpecialDomain('ℕˡᵒᵍ', Domain.NLog = new SpecialDomain("ℕˡᵒᵍ",
x => x/Math.pow(10, x.toString().length-1) % 1 === 0 && x > 0, x => x / Math.pow(10, x.toString().length - 1) % 1 === 0 && x > 0,
function(x) { function(x) {
let x10pow = Math.pow(10, x.toString().length-1) let x10pow = Math.pow(10, x.toString().length - 1)
return Math.max(1, (Math.floor(x/x10pow)+1)*x10pow) return Math.max(1, (Math.floor(x / x10pow) + 1) * x10pow)
}, },
function(x) { function(x) {
let x10pow = Math.pow(10, x.toString().length-1) let x10pow = Math.pow(10, x.toString().length - 1)
return Math.max(1, (Math.ceil(x/x10pow)-1)*x10pow) return Math.max(1, (Math.ceil(x / x10pow) - 1) * x10pow)
}) })
Domain.NLog.latexMarkup = "\\mathbb{N}^{log}" Domain.NLog.latexMarkup = "\\mathbb{N}^{log}"
@ -600,11 +605,11 @@ let refedDomains = []
* @returns {Domain} Parsed domain. * @returns {Domain} Parsed domain.
*/ */
export function parseDomain(domain) { export function parseDomain(domain) {
if(!domain.includes(')') && !domain.includes('(')) return parseDomainSimple(domain) if(!domain.includes(")") && !domain.includes("(")) return parseDomainSimple(domain)
let domStr let domStr
while((domStr = /\(([^)(]+)\)/.exec(domain)) !== null) { while((domStr = /\(([^)(]+)\)/.exec(domain)) !== null) {
let dom = parseDomainSimple(domStr[1].trim()); let dom = parseDomainSimple(domStr[1].trim())
domain = domain.replace(domStr[0], 'D' + refedDomains.length) domain = domain.replace(domStr[0], "D" + refedDomains.length)
refedDomains.push(dom) refedDomains.push(dom)
} }
return parseDomainSimple(domain) return parseDomainSimple(domain)
@ -621,10 +626,10 @@ export function parseDomainSimple(domain) {
if(domain.includes("U") || domain.includes("")) return UnionDomain.import(domain) if(domain.includes("U") || domain.includes("")) return UnionDomain.import(domain)
if(domain.includes("∩")) return IntersectionDomain.import(domain) if(domain.includes("∩")) return IntersectionDomain.import(domain)
if(domain.includes("") || domain.includes("\\")) return MinusDomain.import(domain) if(domain.includes("") || domain.includes("\\")) return MinusDomain.import(domain)
if(domain.charAt(0) === "{" && domain.charAt(domain.length -1) === "}") return DomainSet.import(domain) if(domain.charAt(0) === "{" && domain.charAt(domain.length - 1) === "}") return DomainSet.import(domain)
if(domain.includes("]") || domain.includes("[")) return Range.import(domain) if(domain.includes("]") || domain.includes("[")) return Range.import(domain)
if(["R", "", "N", "", "Z", ""].some(str => domain.toUpperCase().includes(str))) if(["R", "", "N", "", "Z", ""].some(str => domain.toUpperCase().includes(str)))
return Domain.import(domain) return Domain.import(domain)
if(domain[0] === 'D') return refedDomains[parseInt(domain.substr(1))] if(domain[0] === "D") return refedDomains[parseInt(domain.substring(1))]
return new EmptySet() return new EmptySet()
} }

View file

@ -37,28 +37,48 @@ export class Expression {
} }
this.cached = this.isConstant() this.cached = this.isConstant()
this.cachedValue = null this.cachedValue = null
if(this.cached && this.allRequirementsFullfilled()) if(this.cached && this.allRequirementsFulfilled())
this.cachedValue = this.calc.evaluate(Objects.currentObjectsByName) this.cachedValue = this.calc.evaluate(Objects.currentObjectsByName)
this.latexMarkup = Latex.expression(this.calc.tokens) this.latexMarkup = Latex.expression(this.calc.tokens)
} }
/**
* Return all the variables used in calc
* @return {string[]}
*/
variables() { variables() {
return this.calc.variables() return this.calc.variables()
} }
/**
* Checks if the current expression is constant (does not depend on a variable, be it x or n).
* @return {boolean}
*/
isConstant() { isConstant() {
let vars = this.calc.variables() let vars = this.calc.variables()
return !vars.includes("x") && !vars.includes("n") return !vars.includes("x") && !vars.includes("n")
} }
/**
* Returns the list of object names this expression is dependant on.
* @return {string[]}
*/
requiredObjects() { requiredObjects() {
return this.calc.variables().filter(objName => objName !== "x" && objName !== "n") return this.calc.variables().filter(objName => objName !== "x" && objName !== "n")
} }
allRequirementsFullfilled() { /**
* Checks if all the objects required for this expression are defined.
* @return {boolean}
*/
allRequirementsFulfilled() {
return this.requiredObjects().every(objName => objName in Objects.currentObjectsByName) return this.requiredObjects().every(objName => objName in Objects.currentObjectsByName)
} }
/**
* Returns a list of names whose corresponding objects this expression is dependant on and are missing.
* @return {boolean}
*/
undefinedVariables() { undefinedVariables() {
return this.requiredObjects().filter(objName => !(objName in Objects.currentObjectsByName)) return this.requiredObjects().filter(objName => !(objName in Objects.currentObjectsByName))
} }
@ -74,13 +94,13 @@ export class Expression {
this.cachedValue = this.calc.evaluate(Objects.currentObjectsByName) this.cachedValue = this.calc.evaluate(Objects.currentObjectsByName)
return this.cachedValue return this.cachedValue
} }
ExprParser.currentVars = Object.assign({'x': x}, Objects.currentObjectsByName) ExprParser.currentVars = Object.assign({ "x": x }, Objects.currentObjectsByName)
return this.calc.evaluate(ExprParser.currentVars) return this.calc.evaluate(ExprParser.currentVars)
} }
simplify(x) { simplify(x) {
let expr = this.calc.substitute('x', x).simplify() let expr = this.calc.substitute("x", x).simplify()
if(expr.evaluate() === 0) expr = '0' if(expr.evaluate() === 0) expr = "0"
return new Expression(expr) return new Expression(expr)
} }
@ -88,19 +108,19 @@ export class Expression {
return this.calc.toString() return this.calc.toString()
} }
toString(forceSign=false) { toString(forceSign = false) {
let str = Utils.makeExpressionReadable(this.calc.toString()) let str = Utils.makeExpressionReadable(this.calc.toString())
if(str !== undefined && str.match(/^\d*\.\d+$/)) { if(str !== undefined && str.match(/^\d*\.\d+$/)) {
if(str.split('.')[1].split('0').length > 7) { if(str.split(".")[1].split("0").length > 7) {
// Likely rounding error // Likely rounding error
str = parseFloat(str.substring(0, str.length-1)).toString(); str = parseFloat(str.substring(0, str.length - 1)).toString()
} }
} }
if(str[0] !== '-' && forceSign) str = '+' + str if(str[0] !== "-" && forceSign) str = "+" + str
return str return str
} }
} }
export function executeExpression(expr){ export function executeExpression(expr) {
return (new Expression(expr.toString())).execute() return (new Expression(expr.toString())).execute()
} }

View file

@ -17,7 +17,7 @@
*/ */
import { Module } from "./common.mjs" import { Module } from "./common.mjs"
import { FUNCTION, Interface, CanvasInterface, DialogInterface } from "./interface.mjs" import { CanvasInterface, DialogInterface } from "./interface.mjs"
import { textsup } from "../utils.mjs" import { textsup } from "../utils.mjs"
import { Expression } from "../math/index.mjs" import { Expression } from "../math/index.mjs"
import Latex from "./latex.mjs" import Latex from "./latex.mjs"
@ -227,7 +227,7 @@ class CanvasAPI extends Module {
// Drawing throws an error. Generally, it's due to a new modification (or the opening of a file) // Drawing throws an error. Generally, it's due to a new modification (or the opening of a file)
console.error(e) console.error(e)
console.log(e.stack) console.log(e.stack)
this._drawingErrorDialog.showDialog(objType, obj.name, e.message) this._drawingErrorDialog.show(objType, obj.name, e.message)
History.undo() History.undo()
} }
} }

View file

@ -26,7 +26,7 @@ export class Module {
/** /**
* *
* @param {string} name - Name of the API * @param {string} name - Name of the API
* @param {Object.<string, (Interface|string)>} initializationParameters - List of parameters for the initialize function. * @param {Object.<string, (Interface|string|number|boolean)>} initializationParameters - List of parameters for the initialize function.
*/ */
constructor(name, initializationParameters = {}) { constructor(name, initializationParameters = {}) {
console.log(`Loading module ${name}...`) console.log(`Loading module ${name}...`)

View file

@ -55,7 +55,7 @@ class ExprParserAPI extends Module {
* @return {function} JS function to call. * @return {function} JS function to call.
*/ */
parseArgumentsForFunction(args, usage1, usage2) { parseArgumentsForFunction(args, usage1, usage2) {
let f, target, variable let f, variable
if(args.length === 1) { if(args.length === 1) {
// Parse object // Parse object
f = args[0] f = args[0]

View file

@ -17,7 +17,6 @@
*/ */
import { Module } from "./common.mjs" import { Module } from "./common.mjs"
import Latex from "./latex.mjs"
import { HistoryInterface, NUMBER, STRING } from "./interface.mjs" import { HistoryInterface, NUMBER, STRING } from "./interface.mjs"

View file

@ -94,6 +94,10 @@ export class CanvasInterface extends SettingsInterface {
markDirty = FUNCTION markDirty = FUNCTION
/** @type {function(string)} */ /** @type {function(string)} */
loadImage = FUNCTION loadImage = FUNCTION
/** @type {function(string)} */
isImageLoading = FUNCTION
/** @type {function(string)} */
isImageLoaded = FUNCTION
/** @type {function()} */ /** @type {function()} */
requestPaint = FUNCTION requestPaint = FUNCTION
} }

View file

@ -20,7 +20,7 @@ import { Module } from "./common.mjs"
import Objects from "./objects.mjs" import Objects from "./objects.mjs"
import History from "./history.mjs" import History from "./history.mjs"
import Canvas from "./canvas.mjs" import Canvas from "./canvas.mjs"
import { DialogInterface, FUNCTION, Interface, RootInterface, SettingsInterface } from "./interface.mjs" import { DialogInterface, RootInterface, SettingsInterface } from "./interface.mjs"
class IOAPI extends Module { class IOAPI extends Module {

View file

@ -20,7 +20,8 @@ import { Module } from "./common.mjs"
import * as Instruction from "../lib/expr-eval/instruction.mjs" import * as Instruction from "../lib/expr-eval/instruction.mjs"
import { escapeValue } from "../lib/expr-eval/expression.mjs" import { escapeValue } from "../lib/expr-eval/expression.mjs"
const unicodechars = ["α", "β", "γ", "δ", "ε", "ζ", "η", const unicodechars = [
"α", "β", "γ", "δ", "ε", "ζ", "η",
"π", "θ", "κ", "λ", "μ", "ξ", "ρ", "π", "θ", "κ", "λ", "μ", "ξ", "ρ",
"ς", "σ", "τ", "φ", "χ", "ψ", "ω", "ς", "σ", "τ", "φ", "χ", "ψ", "ω",
"Γ", "Δ", "Θ", "Λ", "Ξ", "Π", "Σ", "Γ", "Δ", "Θ", "Λ", "Ξ", "Π", "Σ",
@ -30,7 +31,8 @@ const unicodechars = ["α", "β", "γ", "δ", "ε", "ζ", "η",
"⁷", "⁸", "⁹", "⁰", "₁", "₂", "₃", "⁷", "⁸", "⁹", "⁰", "₁", "₂", "₃",
"₄", "₅", "₆", "₇", "₈", "₉", "₀", "₄", "₅", "₆", "₇", "₈", "₉", "₀",
"pi", "∞"] "pi", "∞"]
const equivalchars = ["\\alpha", "\\beta", "\\gamma", "\\delta", "\\epsilon", "\\zeta", "\\eta", const equivalchars = [
"\\alpha", "\\beta", "\\gamma", "\\delta", "\\epsilon", "\\zeta", "\\eta",
"\\pi", "\\theta", "\\kappa", "\\lambda", "\\mu", "\\xi", "\\rho", "\\pi", "\\theta", "\\kappa", "\\lambda", "\\mu", "\\xi", "\\rho",
"\\sigma", "\\sigma", "\\tau", "\\phi", "\\chi", "\\psi", "\\omega", "\\sigma", "\\sigma", "\\tau", "\\phi", "\\chi", "\\psi", "\\omega",
"\\Gamma", "\\Delta", "\\Theta", "\\Lambda", "\\Xi", "\\Pi", "\\Sigma", "\\Gamma", "\\Delta", "\\Theta", "\\Lambda", "\\Xi", "\\Pi", "\\Sigma",
@ -71,7 +73,7 @@ class LatexAPI extends Module {
* *
* @param {string} markup - LaTeX markup to render. * @param {string} markup - LaTeX markup to render.
* @param {number} fontSize - Font size (in pt) to render. * @param {number} fontSize - Font size (in pt) to render.
* @param {color} color - Color of the text to render. * @param {string} color - Color of the text to render.
* @returns {LatexRenderResult|null} * @returns {LatexRenderResult|null}
*/ */
findPrerendered(markup, fontSize, color) { findPrerendered(markup, fontSize, color) {
@ -87,7 +89,7 @@ class LatexAPI extends Module {
* *
* @param {string} markup - LaTeX markup to render. * @param {string} markup - LaTeX markup to render.
* @param {number} fontSize - Font size (in pt) to render. * @param {number} fontSize - Font size (in pt) to render.
* @param {color} color - Color of the text to render. * @param {string} color - Color of the text to render.
* @returns {Promise<LatexRenderResult>} * @returns {Promise<LatexRenderResult>}
*/ */
async requestAsyncRender(markup, fontSize, color) { async requestAsyncRender(markup, fontSize, color) {
@ -119,7 +121,7 @@ class LatexAPI extends Module {
if(elem[0] !== "(" && elem[elem.length - 1] !== ")" && contents.some(x => elem.indexOf(x) > 0)) if(elem[0] !== "(" && elem[elem.length - 1] !== ")" && contents.some(x => elem.indexOf(x) > 0))
return this.par(elem) return this.par(elem)
if(elem[0] === "(" && elem[elem.length - 1] === ")") if(elem[0] === "(" && elem[elem.length - 1] === ")")
return elem.substr(1, elem.length - 2) return elem.removeEnclosure()
return elem return elem
} }
@ -134,24 +136,24 @@ class LatexAPI extends Module {
switch(f) { switch(f) {
case "derivative": case "derivative":
if(args.length === 3) if(args.length === 3)
return "\\frac{d" + args[0].substr(1, args[0].length - 2).replace(new RegExp(args[1].substr(1, args[1].length - 2), "g"), "x") + "}{dx}" return `\\frac{d${args[0].removeEnclosure().replaceAll(args[1].removeEnclosure(), "x")}}{dx}`
else else
return "\\frac{d" + args[0] + "}{dx}(x)" return `\\frac{d${args[0]}}{dx}(x)`
case "integral": case "integral":
if(args.length === 4) if(args.length === 4)
return "\\int\\limits_{" + args[0] + "}^{" + args[1] + "}" + args[2].substr(1, args[2].length - 2) + " d" + args[3].substr(1, args[3].length - 2) return `\\int\\limits_{${args[0]}}^{${args[1]}}${args[2].removeEnclosure()} d${args[3].removeEnclosure()}`
else else
return "\\int\\limits_{" + args[0] + "}^{" + args[1] + "}" + args[2] + "(t) dt" return `\\int\\limits_{${args[0]}}^{${args[1]}}${args[2]}(t) dt`
case "sqrt": case "sqrt":
return "\\sqrt\\left(" + args.join(", ") + "\\right)" return `\\sqrt\\left(${args.join(", ")}\\right)`
case "abs": case "abs":
return "\\left|" + args.join(", ") + "\\right|" return `\\left|${args.join(", ")}\\right|`
case "floor": case "floor":
return "\\left\\lfloor" + args.join(", ") + "\\right\\rfloor" return `\\left\\lfloor${args.join(", ")}\\right\\rfloor`
case "ceil": case "ceil":
return "\\left\\lceil" + args.join(", ") + "\\right\\rceil" return `\\left\\lceil${args.join(", ")}\\right\\rceil`
default: default:
return "\\mathrm{" + f + "}\\left(" + args.join(", ") + "\\right)" return `\\mathrm{${f}}\\left(${args.join(", ")}\\right)`
} }
} }
@ -166,12 +168,12 @@ class LatexAPI extends Module {
if(wrapIn$) if(wrapIn$)
for(let i = 0; i < unicodechars.length; i++) { for(let i = 0; i < unicodechars.length; i++) {
if(vari.includes(unicodechars[i])) if(vari.includes(unicodechars[i]))
vari = vari.replace(new RegExp(unicodechars[i], "g"), "$" + equivalchars[i] + "$") vari = vari.replaceAll(unicodechars[i], "$" + equivalchars[i] + "$")
} }
else else
for(let i = 0; i < unicodechars.length; i++) { for(let i = 0; i < unicodechars.length; i++) {
if(vari.includes(unicodechars[i])) if(vari.includes(unicodechars[i]))
vari = vari.replace(new RegExp(unicodechars[i], "g"), equivalchars[i]) vari = vari.replaceAll(unicodechars[i], equivalchars[i])
} }
return vari return vari
} }

View file

@ -16,13 +16,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { Module } from './common.mjs' import { Module } from "./common.mjs"
import { textsub } from '../utils.mjs' import { textsub } from "../utils.mjs"
class ObjectsAPI extends Module { class ObjectsAPI extends Module {
constructor() { constructor() {
super('Objects') super("Objects")
this.types = {} this.types = {}
/** /**
@ -45,7 +45,7 @@ class ObjectsAPI extends Module {
* @param {string} prefix - Prefix to the name. * @param {string} prefix - Prefix to the name.
* @return {string} New unused name for a new object. * @return {string} New unused name for a new object.
*/ */
getNewName(allowedLetters, prefix='') { getNewName(allowedLetters, prefix = "") {
// Allows to get a new name, based on the allowed letters, // Allows to get a new name, based on the allowed letters,
// as well as adding a sub number when needs be. // as well as adding a sub number when needs be.
let newid = 0 let newid = 0
@ -53,7 +53,7 @@ class ObjectsAPI extends Module {
do { do {
let letter = allowedLetters[newid % allowedLetters.length] let letter = allowedLetters[newid % allowedLetters.length]
let num = Math.floor((newid - (newid % allowedLetters.length)) / allowedLetters.length) let num = Math.floor((newid - (newid % allowedLetters.length)) / allowedLetters.length)
ret = prefix + letter + (num > 0 ? textsub(num-1) : '') ret = prefix + letter + (num > 0 ? textsub(num - 1) : "")
newid += 1 newid += 1
} while(ret in this.currentObjectsByName) } while(ret in this.currentObjectsByName)
return ret return ret
@ -78,7 +78,7 @@ class ObjectsAPI extends Module {
deleteObject(objName) { deleteObject(objName) {
let obj = this.currentObjectsByName[objName] let obj = this.currentObjectsByName[objName]
if(obj !== undefined) { if(obj !== undefined) {
this.currentObjects[obj.type].splice(this.currentObjects[obj.type].indexOf(obj),1) this.currentObjects[obj.type].splice(this.currentObjects[obj.type].indexOf(obj), 1)
obj.delete() obj.delete()
delete this.currentObjectsByName[objName] delete this.currentObjectsByName[objName]
} }
@ -90,15 +90,10 @@ class ObjectsAPI extends Module {
* @returns {string[]} List of names of the objects. * @returns {string[]} List of names of the objects.
*/ */
getObjectsName(objType) { getObjectsName(objType) {
if(objType === "ExecutableObject") { if(objType === "ExecutableObject")
// NOTE: QMLJS does not support flatMap. return this.getExecutableTypes().flatMap(
// return getExecutableTypes().flatMap(elemType => currentObjects[elemType].map(obj => obj.name)) elemType => this.currentObjects[elemType].map(obj => obj.name)
let types = this.getExecutableTypes() )
let elementNames = ['']
for(let elemType of types)
elementNames = elementNames.concat(this.currentObjects[elemType].map(obj => obj.name))
return elementNames
}
if(this.currentObjects[objType] === undefined) return [] if(this.currentObjects[objType] === undefined) return []
return this.currentObjects[objType].map(obj => obj.name) return this.currentObjects[objType].map(obj => obj.name)
} }
@ -117,9 +112,9 @@ class ObjectsAPI extends Module {
* @param {string[]} args - List of arguments for the objects (can be empty). * @param {string[]} args - List of arguments for the objects (can be empty).
* @return {DrawableObject<objType>} Newly created object. * @return {DrawableObject<objType>} Newly created object.
*/ */
createNewRegisteredObject(objType, args= []) { createNewRegisteredObject(objType, args = []) {
if(Object.keys(this.types).indexOf(objType) === -1) return null // Object type does not exist. if(Object.keys(this.types).indexOf(objType) === -1) return null // Object type does not exist.
let newobj = new this.types[objType](...args) const newobj = new this.types[objType](...args)
if(Object.keys(this.currentObjects).indexOf(objType) === -1) { if(Object.keys(this.currentObjects).indexOf(objType) === -1) {
this.currentObjects[objType] = [] this.currentObjects[objType] = []
} }

View file

@ -15,19 +15,19 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import {Module} from "./common.mjs" import { Module } from "./common.mjs"
import General from "../preferences/general.mjs" import General from "../preferences/general.mjs"
import Editor from "../preferences/expression.mjs" import Editor from "../preferences/expression.mjs"
import DefaultGraph from "../preferences/default.mjs" import DefaultGraph from "../preferences/default.mjs"
class PreferencesAPI extends Module { class PreferencesAPI extends Module {
constructor() { constructor() {
super('Preferences') super("Preferences")
this.categories = { this.categories = {
[QT_TRANSLATE_NOOP('settingCategory', 'general')]: General, [QT_TRANSLATE_NOOP("settingCategory", "general")]: General,
[QT_TRANSLATE_NOOP('settingCategory', 'editor')]: Editor, [QT_TRANSLATE_NOOP("settingCategory", "editor")]: Editor,
[QT_TRANSLATE_NOOP('settingCategory', 'default')]: DefaultGraph, [QT_TRANSLATE_NOOP("settingCategory", "default")]: DefaultGraph
} }
} }
} }

View file

@ -27,39 +27,50 @@ import { ExecutableObject } from "./common.mjs"
import Function from "./function.mjs" import Function from "./function.mjs"
export default class BodeMagnitude extends ExecutableObject { export default class BodeMagnitude extends ExecutableObject {
static type(){return 'Gain Bode'} static type() {
static displayType(){return qsTranslate("bodemagnitude", 'Bode Magnitude')} return "Gain Bode"
static displayTypeMultiple(){return qsTranslate("bodemagnitude", 'Bode Magnitudes')} }
static properties() {return {
[QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'),
[QT_TRANSLATE_NOOP('prop','pass')]: P.Enum.BodePass,
[QT_TRANSLATE_NOOP('prop','gain')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
[QT_TRANSLATE_NOOP('prop','omGraduation')]: 'boolean'
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value', static displayType() {
om_0 = '', pass = 'high', gain = '20', labelPosition = 'above', labelX = 1, omGraduation = false) { return qsTranslate("bodemagnitude", "Bode Magnitude")
if(name == null) name = Objects.getNewName('G') }
if(name === 'G') name = 'G₀' // G is reserved for sum of BODE magnitudes (Somme gains Bode).
static displayTypeMultiple() {
return qsTranslate("bodemagnitude", "Bode Magnitudes")
}
static properties() {
return {
[QT_TRANSLATE_NOOP("prop", "om_0")]: new P.ObjectType("Point"),
[QT_TRANSLATE_NOOP("prop", "pass")]: P.Enum.BodePass,
[QT_TRANSLATE_NOOP("prop", "gain")]: new P.Expression(),
[QT_TRANSLATE_NOOP("prop", "labelPosition")]: P.Enum.Position,
[QT_TRANSLATE_NOOP("prop", "labelX")]: "number",
[QT_TRANSLATE_NOOP("prop", "omGraduation")]: "boolean"
}
}
constructor(name = null, visible = true, color = null, labelContent = "name + value",
om_0 = "", pass = "high", gain = "20", labelPosition = "above", labelX = 1, omGraduation = false) {
if(name == null) name = Objects.getNewName("G")
if(name === "G") name = "G₀" // G is reserved for sum of BODE magnitudes (Somme gains Bode).
super(name, visible, color, labelContent) super(name, visible, color, labelContent)
if(typeof om_0 == "string") { if(typeof om_0 == "string") {
// Point name or create one // Point name or create one
om_0 = Objects.currentObjectsByName[om_0] om_0 = Objects.currentObjectsByName[om_0]
if(om_0 == null) { if(om_0 == null) {
// Create new point // Create new point
om_0 = Objects.createNewRegisteredObject('Point', [Objects.getNewName('ω'), true, this.color, 'name']) om_0 = Objects.createNewRegisteredObject("Point", [Objects.getNewName("ω"), true, this.color, "name"])
History.addToHistory(new CreateNewObject(om_0.name, 'Point', om_0.export())) History.addToHistory(new CreateNewObject(om_0.name, "Point", om_0.export()))
om_0.update() om_0.update()
labelPosition = 'below' labelPosition = "below"
} }
om_0.requiredBy.push(this) om_0.requiredBy.push(this)
} }
/** @type {Point} */ /** @type {Point} */
this.om_0 = om_0 this.om_0 = om_0
this.pass = pass this.pass = pass
if(typeof gain == 'number' || typeof gain == 'string') gain = new Expression(gain.toString()) if(typeof gain == "number" || typeof gain == "string") gain = new Expression(gain.toString())
this.gain = gain this.gain = gain
this.labelPosition = labelPosition this.labelPosition = labelPosition
this.labelX = labelX this.labelX = labelX
@ -67,21 +78,21 @@ export default class BodeMagnitude extends ExecutableObject {
} }
getReadableString() { getReadableString() {
let pass = this.pass === "low" ? qsTranslate("bodemagnitude", "low-pass") : qsTranslate("bodemagnitude", "high-pass"); let pass = this.pass === "low" ? qsTranslate("bodemagnitude", "low-pass") : qsTranslate("bodemagnitude", "high-pass")
return `${this.name}: ${pass}; ${this.om_0.name} = ${this.om_0.x}\n ${' '.repeat(this.name.length)}${this.gain.toString(true)} dB/dec` return `${this.name}: ${pass}; ${this.om_0.name} = ${this.om_0.x}\n ${" ".repeat(this.name.length)}${this.gain.toString(true)} dB/dec`
} }
getLatexString() { getLatexString() {
let pass = this.pass === "low" ? qsTranslate("bodemagnitude", "low-pass") : qsTranslate("bodemagnitude", "high-pass"); let pass = this.pass === "low" ? qsTranslate("bodemagnitude", "low-pass") : qsTranslate("bodemagnitude", "high-pass")
return `\\mathrm{${Latex.variable(this.name)}:}\\begin{array}{l} return `\\mathrm{${Latex.variable(this.name)}:}\\begin{array}{l}
\\textsf{${pass}};${Latex.variable(this.om_0.name)} = ${this.om_0.x.latexMarkup} \\\\ \\textsf{${pass}};${Latex.variable(this.om_0.name)} = ${this.om_0.x.latexMarkup} \\\\
${this.gain.latexMarkup}\\textsf{ dB/dec} ${this.gain.latexMarkup}\\textsf{ dB/dec}
\\end{array}` \\end{array}`
} }
execute(x=1) { execute(x = 1) {
if(typeof x == 'string') x = executeExpression(x) if(typeof x == "string") x = executeExpression(x)
if((this.pass === 'high' && x < this.om_0.x) || (this.pass === 'low' && x > this.om_0.x)) { if((this.pass === "high" && x < this.om_0.x) || (this.pass === "low" && x > this.om_0.x)) {
let dbfn = new Expression(`${this.gain.execute()}*(ln(x)-ln(${this.om_0.x}))/ln(10)+${this.om_0.y}`) let dbfn = new Expression(`${this.gain.execute()}*(ln(x)-ln(${this.om_0.x}))/ln(10)+${this.om_0.y}`)
return dbfn.execute(x) return dbfn.execute(x)
} else { } else {
@ -91,8 +102,8 @@ export default class BodeMagnitude extends ExecutableObject {
simplify(x = 1) { simplify(x = 1) {
let xval = x let xval = x
if(typeof x == 'string') xval = executeExpression(x) if(typeof x == "string") xval = executeExpression(x)
if((this.pass === 'high' && xval < this.om_0.x.execute()) || (this.pass === 'low' && xval > this.om_0.x.execute())) { if((this.pass === "high" && xval < this.om_0.x.execute()) || (this.pass === "low" && xval > this.om_0.x.execute())) {
let dbfn = new Expression(`${this.gain.execute()}*(ln(x)-ln(${this.om_0.x}))/ln(10)+${this.om_0.y}`) let dbfn = new Expression(`${this.gain.execute()}*(ln(x)-ln(${this.om_0.x}))/ln(10)+${this.om_0.y}`)
return dbfn.simplify(x) return dbfn.simplify(x)
} else { } else {
@ -107,9 +118,9 @@ export default class BodeMagnitude extends ExecutableObject {
draw(canvas) { draw(canvas) {
let base = [canvas.x2px(this.om_0.x.execute()), canvas.y2px(this.om_0.y.execute())] let base = [canvas.x2px(this.om_0.x.execute()), canvas.y2px(this.om_0.y.execute())]
let dbfn = new Expression(`${this.gain.execute()}*(log10(x)-log10(${this.om_0.x}))+${this.om_0.y}`) let dbfn = new Expression(`${this.gain.execute()}*(log10(x)-log10(${this.om_0.x}))+${this.om_0.y}`)
let inDrawDom = new EmptySet() let inDrawDom
if(this.pass === 'high') { if(this.pass === "high") {
// High pass, linear line from beginning, then constant to the end. // High pass, linear line from beginning, then constant to the end.
canvas.drawLine(base[0], base[1], canvas.width, base[1]) canvas.drawLine(base[0], base[1], canvas.width, base[1])
inDrawDom = parseDomain(`]-inf;${this.om_0.x}[`) inDrawDom = parseDomain(`]-inf;${this.om_0.x}[`)
@ -122,8 +133,8 @@ export default class BodeMagnitude extends ExecutableObject {
// Dashed line representing break in function // Dashed line representing break in function
let xpos = canvas.x2px(this.om_0.x.execute()) let xpos = canvas.x2px(this.om_0.x.execute())
let dashPxSize = 10 let dashPxSize = 10
for(let i = 0; i < canvas.height && this.omGraduation; i += dashPxSize*2) for(let i = 0; i < canvas.height && this.omGraduation; i += dashPxSize * 2)
canvas.drawLine(xpos, i, xpos, i+dashPxSize) canvas.drawLine(xpos, i, xpos, i + dashPxSize)
// Label // Label
this.drawLabel(canvas, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX))) this.drawLabel(canvas, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX)))
@ -131,17 +142,19 @@ export default class BodeMagnitude extends ExecutableObject {
update() { update() {
super.update() super.update()
let sumObjs = Objects.currentObjects['Somme gains Bode'] /** @type {BodeMagnitudeSum[]} */
let sumObjs = Objects.currentObjects["Somme gains Bode"]
if(sumObjs !== undefined && sumObjs.length > 0) { if(sumObjs !== undefined && sumObjs.length > 0) {
sumObjs[0].recalculateCache() sumObjs[0].recalculateCache()
} else { } else {
Objects.createNewRegisteredObject('Somme gains Bode') Objects.createNewRegisteredObject("Somme gains Bode")
} }
} }
delete() { delete() {
super.delete() super.delete()
let sumObjs = Objects.currentObjects['Somme gains Bode'] /** @type {BodeMagnitudeSum[]} */
let sumObjs = Objects.currentObjects["Somme gains Bode"]
if(sumObjs !== undefined && sumObjs.length > 0) { if(sumObjs !== undefined && sumObjs.length > 0) {
sumObjs[0].recalculateCache() sumObjs[0].recalculateCache()
} }

View file

@ -26,18 +26,32 @@ import Function from "./function.mjs"
export default class BodeMagnitudeSum extends ExecutableObject { export default class BodeMagnitudeSum extends ExecutableObject {
static type(){return 'Somme gains Bode'} static type() {
static displayType(){return qsTranslate("bodemagnitudesum", 'Bode Magnitudes Sum')} return "Somme gains Bode"
static displayTypeMultiple(){return qsTranslate("bodemagnitudesum", 'Bode Magnitudes Sum')} }
static createable() {return false}
static properties() {return {
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value', static displayType() {
labelPosition = 'above', labelX = 1) { return qsTranslate("bodemagnitudesum", "Bode Magnitudes Sum")
if(name == null) name = 'G' }
static displayTypeMultiple() {
return qsTranslate("bodemagnitudesum", "Bode Magnitudes Sum")
}
static createable() {
return false
}
static properties() {
return {
[QT_TRANSLATE_NOOP("prop", "labelPosition")]: P.Enum.Position,
[QT_TRANSLATE_NOOP("prop", "labelX")]: "number"
}
}
constructor(name = null, visible = true, color = null, labelContent = "name + value",
labelPosition = "above", labelX = 1) {
if(name == null) name = "G"
super(name, visible, color, labelContent) super(name, visible, color, labelContent)
this.labelPosition = labelPosition this.labelPosition = labelPosition
this.labelX = labelX this.labelX = labelX
@ -45,11 +59,11 @@ export default class BodeMagnitudeSum extends ExecutableObject {
} }
getReadableString() { getReadableString() {
return `${this.name} = ${Objects.getObjectsName('Gain Bode').join(' + ')}` return `${this.name} = ${Objects.getObjectsName("Gain Bode").join(" + ")}`
} }
getLatexString() { getLatexString() {
return `${Latex.variable(this.name)} = ${Objects.getObjectsName('Gain Bode').map(name => Latex.variable(name)).join(' + ')}` return `${Latex.variable(this.name)} = ${Objects.getObjectsName("Gain Bode").map(name => Latex.variable(name)).join(" + ")}`
} }
execute(x = 0) { execute(x = 0) {
@ -71,17 +85,17 @@ export default class BodeMagnitudeSum extends ExecutableObject {
return limitedDrawFunction.simplify(x) return limitedDrawFunction.simplify(x)
} }
} }
return '' return ""
} }
recalculateCache() { recalculateCache() {
this.cachedParts = [] this.cachedParts = []
// Calculating this is fairly resource expansive so it's cached. // Calculating this is fairly resource expansive so it's cached.
let magnitudeObjects = Objects.currentObjects['Gain Bode'] let magnitudeObjects = Objects.currentObjects["Gain Bode"]
if(magnitudeObjects === undefined || magnitudeObjects.length < 1) { if(magnitudeObjects === undefined || magnitudeObjects.length < 1) {
Objects.deleteObject(this.name) Objects.deleteObject(this.name)
} else { } else {
console.log('Recalculating cache gain') console.log("Recalculating cache gain")
// Minimum to draw (can be expended if needed, just not infinite or it'll cause issues. // Minimum to draw (can be expended if needed, just not infinite or it'll cause issues.
const MIN_DRAW = 1e-20 const MIN_DRAW = 1e-20
// Format: [[x value of where the filter transitions, magnitude, high-pass (bool)]] // Format: [[x value of where the filter transitions, magnitude, high-pass (bool)]]
@ -92,18 +106,18 @@ export default class BodeMagnitudeSum extends ExecutableObject {
magnitudes.push([Number.MAX_VALUE, 0, true]) // Draw the ending section magnitudes.push([Number.MAX_VALUE, 0, true]) // Draw the ending section
// Collect data from current magnitude (or gain in French) objects. // Collect data from current magnitude (or gain in French) objects.
let baseY = 0 let baseY = 0
for(/** @type {Bodemagnitude} */ let magnitudeObj of magnitudeObjects) { // Sorting by their om_0 position. for(/** @type {BodeMagnitude} */ let magnitudeObj of magnitudeObjects) { // Sorting by their om_0 position.
const om0x = magnitudeObj.om_0.x.execute() const om0x = magnitudeObj.om_0.x.execute()
magnitudes.push([om0x, magnitudeObj.gain.execute(), magnitudeObj.pass === 'high']) magnitudes.push([om0x, magnitudeObj.gain.execute(), magnitudeObj.pass === "high"])
baseY += magnitudeObj.execute(MIN_DRAW) baseY += magnitudeObj.execute(MIN_DRAW)
} }
// Sorting the data by their x transitions value // Sorting the data by their x transitions value
magnitudes.sort((a,b) => a[XVALUE] - b[XVALUE]) magnitudes.sort((a, b) => a[XVALUE] - b[XVALUE])
// Adding the total gains. // Adding the total gains.
let magnitudesBeforeTransition = [] let magnitudesBeforeTransition = []
let magnitudesAfterTransition = [] let magnitudesAfterTransition = []
let totalMagnitudeAtStart = 0 // Magnitude at the lowest x value (sum of all high-pass magnitudes) let totalMagnitudeAtStart = 0 // Magnitude at the lowest x value (sum of all high-pass magnitudes)
for(let [om0x, magnitude, highpass] of magnitudes){ for(let [om0x, magnitude, highpass] of magnitudes) {
if(highpass) { if(highpass) {
magnitudesBeforeTransition.push(magnitude) magnitudesBeforeTransition.push(magnitude)
magnitudesAfterTransition.push(0) magnitudesAfterTransition.push(0)

View file

@ -27,33 +27,44 @@ import { ExecutableObject } from "./common.mjs"
export default class BodePhase extends ExecutableObject { export default class BodePhase extends ExecutableObject {
static type(){return 'Phase Bode'} static type() {
static displayType(){return qsTranslate("bodephase", 'Bode Phase')} return "Phase Bode"
static displayTypeMultiple(){return qsTranslate("bodephase", 'Bode Phases')} }
static properties() {return {
[QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'),
[QT_TRANSLATE_NOOP('prop','phase')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','unit')]: new P.Enum('°', 'deg', 'rad'),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number'
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value', static displayType() {
om_0 = '', phase = 90, unit = '°', labelPosition = 'above', labelX = 1) { return qsTranslate("bodephase", "Bode Phase")
if(name == null) name = Objects.getNewName('φ') }
if(name === 'φ') name = 'φ₀' // φ is reserved for sum of Bode phases.
static displayTypeMultiple() {
return qsTranslate("bodephase", "Bode Phases")
}
static properties() {
return {
[QT_TRANSLATE_NOOP("prop", "om_0")]: new P.ObjectType("Point"),
[QT_TRANSLATE_NOOP("prop", "phase")]: new P.Expression(),
[QT_TRANSLATE_NOOP("prop", "unit")]: new P.Enum("°", "deg", "rad"),
[QT_TRANSLATE_NOOP("prop", "labelPosition")]: P.Enum.Position,
[QT_TRANSLATE_NOOP("prop", "labelX")]: "number"
}
}
constructor(name = null, visible = true, color = null, labelContent = "name + value",
om_0 = "", phase = 90, unit = "°", labelPosition = "above", labelX = 1) {
if(name == null) name = Objects.getNewName("φ")
if(name === "φ") name = "φ₀" // φ is reserved for sum of Bode phases.
super(name, visible, color, labelContent) super(name, visible, color, labelContent)
if(typeof phase == 'number' || typeof phase == 'string') phase = new Expression(phase.toString()) if(typeof phase == "number" || typeof phase == "string") phase = new Expression(phase.toString())
this.phase = phase this.phase = phase
if(typeof om_0 == "string") { if(typeof om_0 == "string") {
// Point name or create one // Point name or create one
om_0 = Objects.currentObjectsByName[om_0] om_0 = Objects.currentObjectsByName[om_0]
if(om_0 == null) { if(om_0 == null) {
// Create new point // Create new point
om_0 = Objects.createNewRegisteredObject('Point', [Objects.getNewName('ω'), this.color, 'name']) om_0 = Objects.createNewRegisteredObject("Point", [Objects.getNewName("ω"), this.color, "name"])
om_0.labelPosition = this.phase.execute() >= 0 ? 'above' : 'below' om_0.labelPosition = this.phase.execute() >= 0 ? "above" : "below"
History.history.addToHistory(new CreateNewObject(om_0.name, 'Point', om_0.export())) History.history.addToHistory(new CreateNewObject(om_0.name, "Point", om_0.export()))
labelPosition = 'below' labelPosition = "below"
} }
om_0.requiredBy.push(this) om_0.requiredBy.push(this)
} }
@ -72,8 +83,8 @@ export default class BodePhase extends ExecutableObject {
return `${Latex.variable(this.name)}: ${this.phase.latexMarkup}\\textsf{${this.unit} at }${Latex.variable(this.om_0.name)} = ${this.om_0.x.latexMarkup}` return `${Latex.variable(this.name)}: ${this.phase.latexMarkup}\\textsf{${this.unit} at }${Latex.variable(this.om_0.name)} = ${this.om_0.x.latexMarkup}`
} }
execute(x=1) { execute(x = 1) {
if(typeof x == 'string') x = executeExpression(x) if(typeof x == "string") x = executeExpression(x)
if(x < this.om_0.x) { if(x < this.om_0.x) {
return this.om_0.y.execute() return this.om_0.y.execute()
} else { } else {
@ -83,11 +94,11 @@ export default class BodePhase extends ExecutableObject {
simplify(x = 1) { simplify(x = 1) {
let xval = x let xval = x
if(typeof x == 'string') xval = executeExpression(x) if(typeof x == "string") xval = executeExpression(x)
if(xval < this.om_0.x) { if(xval < this.om_0.x) {
return this.om_0.y.toString() return this.om_0.y.toString()
} else { } else {
let newExp = this.om_0.y.toEditableString() + ' + ' + this.phase.toEditableString() let newExp = this.om_0.y.toEditableString() + " + " + this.phase.toEditableString()
return new Expression(newExp) return new Expression(newExp)
} }
} }
@ -101,7 +112,7 @@ export default class BodePhase extends ExecutableObject {
let omy = this.om_0.y.execute() let omy = this.om_0.y.execute()
let augmt = this.phase.execute() let augmt = this.phase.execute()
let baseY = canvas.y2px(omy) let baseY = canvas.y2px(omy)
let augmtY = canvas.y2px(omy+augmt) let augmtY = canvas.y2px(omy + augmt)
// Before change line. // Before change line.
canvas.drawLine(0, baseY, Math.min(baseX, canvas.height), baseY) canvas.drawLine(0, baseY, Math.min(baseX, canvas.height), baseY)
// Transition line. // Transition line.
@ -115,17 +126,19 @@ export default class BodePhase extends ExecutableObject {
update() { update() {
super.update() super.update()
let sumObjs = Objects.currentObjects['Somme phases Bode'] /** @type {BodePhaseSum[]} */
let sumObjs = Objects.currentObjects["Somme phases Bode"]
if(sumObjs !== undefined && sumObjs.length > 0) { if(sumObjs !== undefined && sumObjs.length > 0) {
sumObjs[0].recalculateCache() sumObjs[0].recalculateCache()
} else { } else {
Objects.createNewRegisteredObject('Somme phases Bode') Objects.createNewRegisteredObject("Somme phases Bode")
} }
} }
delete() { delete() {
super.update() super.update()
let sumObjs = Objects.currentObjects['Somme phases Bode'] /** @type {BodePhaseSum[]} */
let sumObjs = Objects.currentObjects["Somme phases Bode"]
if(sumObjs !== undefined && sumObjs.length > 0) { if(sumObjs !== undefined && sumObjs.length > 0) {
sumObjs[0].recalculateCache() sumObjs[0].recalculateCache()
} }

View file

@ -24,18 +24,32 @@ import Latex from "../module/latex.mjs"
import { ExecutableObject } from "./common.mjs" import { ExecutableObject } from "./common.mjs"
export default class BodePhaseSum extends ExecutableObject { export default class BodePhaseSum extends ExecutableObject {
static type(){return 'Somme phases Bode'} static type() {
static displayType(){return qsTranslate("bodephasesum", 'Bode Phases Sum')} return "Somme phases Bode"
static displayTypeMultiple(){return qsTranslate("bodephasesum", 'Bode Phases Sum')} }
static createable() {return false}
static properties() {return {
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value', static displayType() {
labelPosition = 'above', labelX = 1) { return qsTranslate("bodephasesum", "Bode Phases Sum")
if(name == null) name = 'φ' }
static displayTypeMultiple() {
return qsTranslate("bodephasesum", "Bode Phases Sum")
}
static createable() {
return false
}
static properties() {
return {
[QT_TRANSLATE_NOOP("prop", "labelPosition")]: P.Enum.Position,
[QT_TRANSLATE_NOOP("prop", "labelX")]: "number"
}
}
constructor(name = null, visible = true, color = null, labelContent = "name + value",
labelPosition = "above", labelX = 1) {
if(name == null) name = "φ"
super(name, visible, color, labelContent) super(name, visible, color, labelContent)
this.labelPosition = labelPosition this.labelPosition = labelPosition
this.labelX = labelX this.labelX = labelX
@ -43,29 +57,29 @@ export default class BodePhaseSum extends ExecutableObject {
} }
getReadableString() { getReadableString() {
return `${this.name} = ${Objects.getObjectsName('Phase Bode').join(' + ')}` return `${this.name} = ${Objects.getObjectsName("Phase Bode").join(" + ")}`
} }
getLatexString() { getLatexString() {
return `${Latex.variable(this.name)} = ${Objects.getObjectsName('Phase Bode').map(name => Latex.variable(name)).join(' + ')}` return `${Latex.variable(this.name)} = ${Objects.getObjectsName("Phase Bode").map(name => Latex.variable(name)).join(" + ")}`
} }
execute(x=1) { execute(x = 1) {
if(typeof x == 'string') x = executeExpression(x) if(typeof x == "string") x = executeExpression(x)
for(let i = 0; i < this.om0xList.length-1; i++) { for(let i = 0; i < this.om0xList.length - 1; i++) {
if(x >= this.om0xList[i] && x < this.om0xList[i+1]) return this.phasesList[i] if(x >= this.om0xList[i] && x < this.om0xList[i + 1]) return this.phasesList[i]
} }
} }
simplify(x = 1) { simplify(x = 1) {
let xval = x let xval = x
if(typeof x == 'string') xval = executeExpression(x) if(typeof x == "string") xval = executeExpression(x)
for(let i = 0; i < this.om0xList.length-1; i++) { for(let i = 0; i < this.om0xList.length - 1; i++) {
if(xval >= this.om0xList[i] && xval < this.om0xList[i+1]) { if(xval >= this.om0xList[i] && xval < this.om0xList[i + 1]) {
return (new Expression(this.phasesExprList[i])).simplify() return (new Expression(this.phasesExprList[i])).simplify()
} }
} }
return '0' return "0"
} }
canExecute(x = 1) { canExecute(x = 1) {
@ -78,43 +92,42 @@ export default class BodePhaseSum extends ExecutableObject {
let drawMax = 1e20 let drawMax = 1e20
this.om0xList = [drawMin, drawMax] this.om0xList = [drawMin, drawMax]
this.phasesList = [0] this.phasesList = [0]
this.phasesExprList = ['0'] this.phasesExprList = ["0"]
let phasesDict = new Map() let phasesDict = new Map()
let phasesExprDict = new Map() let phasesExprDict = new Map()
phasesDict.set(drawMax, 0) phasesDict.set(drawMax, 0)
let phaseObjects = Objects.currentObjects['Phase Bode'] let phaseObjects = Objects.currentObjects["Phase Bode"]
if(phaseObjects === undefined || phaseObjects.length < 1) { if(phaseObjects === undefined || phaseObjects.length < 1) {
Objects.deleteObject(this.name) Objects.deleteObject(this.name)
} else { } else {
console.log('Recalculating cache phase') console.log("Recalculating cache phase")
for(/** @type {Bodephase} */ let obj of phaseObjects) { for(/** @type {BodePhase} */ let obj of phaseObjects) {
this.om0xList.push(obj.om_0.x.execute()) this.om0xList.push(obj.om_0.x.execute())
if(!phasesDict.has(obj.om_0.x.execute())) { if(!phasesDict.has(obj.om_0.x.execute())) {
phasesDict.set(obj.om_0.x.execute(), obj.phase.execute()) phasesDict.set(obj.om_0.x.execute(), obj.phase.execute())
phasesExprDict.set(obj.om_0.x.execute(), obj.phase.toEditableString()) phasesExprDict.set(obj.om_0.x.execute(), obj.phase.toEditableString())
} else { } else {
phasesDict.set(obj.om_0.x.execute(), obj.phase.execute() + phasesDict.get(obj.om_0.x.execute())) phasesDict.set(obj.om_0.x.execute(), obj.phase.execute() + phasesDict.get(obj.om_0.x.execute()))
phasesExprDict.set(obj.om_0.x.execute(), obj.phase.toEditableString() + '+' + phasesExprDict.get(obj.om_0.x.execute())) phasesExprDict.set(obj.om_0.x.execute(), obj.phase.toEditableString() + "+" + phasesExprDict.get(obj.om_0.x.execute()))
} }
this.phasesList[0] += obj.om_0.y.execute() this.phasesList[0] += obj.om_0.y.execute()
this.phasesExprList[0] += '+' + obj.om_0.y.toEditableString() this.phasesExprList[0] += "+" + obj.om_0.y.toEditableString()
} }
this.om0xList.sort((a,b) => a - b) this.om0xList.sort((a, b) => a - b)
let totalAdded = this.phasesList[0]
for(let i = 1; i < this.om0xList.length; i++) { for(let i = 1; i < this.om0xList.length; i++) {
this.phasesList[i] = this.phasesList[i-1] + phasesDict.get(this.om0xList[i]) this.phasesList[i] = this.phasesList[i - 1] + phasesDict.get(this.om0xList[i])
this.phasesExprList[i] = this.phasesExprList[i-1] + '+' + phasesDict.get(this.om0xList[i]) this.phasesExprList[i] = this.phasesExprList[i - 1] + "+" + phasesDict.get(this.om0xList[i])
} }
} }
} }
draw(canvas) { draw(canvas) {
for(let i = 0; i < this.om0xList.length-1; i++) { for(let i = 0; i < this.om0xList.length - 1; i++) {
let om0xBegin = canvas.x2px(this.om0xList[i]) let om0xBegin = canvas.x2px(this.om0xList[i])
let om0xEnd = canvas.x2px(this.om0xList[i+1]) let om0xEnd = canvas.x2px(this.om0xList[i + 1])
let baseY = canvas.y2px(this.phasesList[i]) let baseY = canvas.y2px(this.phasesList[i])
let nextY = canvas.y2px(this.phasesList[i+1]) let nextY = canvas.y2px(this.phasesList[i + 1])
canvas.drawLine(om0xBegin, baseY, om0xEnd, baseY) canvas.drawLine(om0xBegin, baseY, om0xEnd, baseY)
canvas.drawLine(om0xEnd, baseY, om0xEnd, nextY) canvas.drawLine(om0xEnd, baseY, om0xEnd, nextY)
} }

View file

@ -16,10 +16,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { getRandomColor, textsub } from "../utils.mjs" import { getRandomColor } from "../utils.mjs"
import Objects from "../module/objects.mjs" import Objects from "../module/objects.mjs"
import Latex from "../module/latex.mjs" import Latex from "../module/latex.mjs"
import {ensureTypeSafety, serializesByPropertyType} from "../parameters.mjs" import { ensureTypeSafety, serializesByPropertyType } from "../parameters.mjs"
// This file contains the default data to be imported from all other objects // This file contains the default data to be imported from all other objects
@ -32,26 +32,34 @@ export class DrawableObject {
* Base name of the object. Needs to be constant over time. * Base name of the object. Needs to be constant over time.
* @return {string} Type of the object. * @return {string} Type of the object.
*/ */
static type(){return 'Unknown'} static type() {
return "Unknown"
}
/** /**
* Translated name of the object to be shown to the user. * Translated name of the object to be shown to the user.
* @return {string} * @return {string}
*/ */
static displayType(){return 'Unknown'} static displayType() {
return "Unknown"
}
/** /**
* Translated name of the object in plural form to be shown to the user. * Translated name of the object in plural form to be shown to the user.
* @return {string} * @return {string}
*/ */
static displayTypeMultiple(){return 'Unknowns'} static displayTypeMultiple() {
return "Unknowns"
}
/** /**
* True if this object can be created by the user, false if it can only * True if this object can be created by the user, false if it can only
* be instantiated by other objects * be instantiated by other objects
* @return {boolean} * @return {boolean}
*/ */
static createable() {return true} static createable() {
return true
}
/** /**
* List of properties used in the Object Editor. * List of properties used in the Object Editor.
@ -70,14 +78,18 @@ export class DrawableObject {
* *
* @return {Object.<string,string|Enum|List|ObjectType|Dictionary>} * @return {Object.<string,string|Enum|List|ObjectType|Dictionary>}
*/ */
static properties() {return {}} static properties() {
return {}
}
/** /**
* True if this object can be executed, so that an y value might be computed * True if this object can be executed, so that an y value might be computed
* for an x value. Only ExecutableObjects have that property set to true. * for an x value. Only ExecutableObjects have that property set to true.
* @return {boolean} * @return {boolean}
*/ */
static executable() {return false} static executable() {
return false
}
/** /**
* Imports the object from its serialized form. * Imports the object from its serialized form.
@ -85,10 +97,10 @@ export class DrawableObject {
*/ */
static import(name, visible, color, labelContent, ...args) { static import(name, visible, color, labelContent, ...args) {
let importedArgs = [name.toString(), visible === true, color.toString(), labelContent] let importedArgs = [name.toString(), visible === true, color.toString(), labelContent]
console.log('Importing', this.type(), name, args) console.log("Importing", this.type(), name, args)
for(let [name, propType] of Object.entries(this.properties())) for(let [name, propType] of Object.entries(this.properties()))
if(!name.startsWith('comment')) { if(!name.startsWith("comment")) {
importedArgs.push(ensureTypeSafety(propType, args[importedArgs.length-4])) importedArgs.push(ensureTypeSafety(propType, args[importedArgs.length - 4]))
} }
return new this(...importedArgs) return new this(...importedArgs)
} }
@ -98,10 +110,10 @@ export class DrawableObject {
* @param {string} name - Name of the object * @param {string} name - Name of the object
* @param {boolean} visible - true if the object is visible, false otherwise. * @param {boolean} visible - true if the object is visible, false otherwise.
* @param {color|string} color - Color of the object (can be string or QColor) * @param {color|string} color - Color of the object (can be string or QColor)
* @param {'null'|'name'|'name + value'} labelContent - One of 'null', 'name' or 'name + value' describing the content of the label. * @param {"null"|"name"|"name + value"} labelContent - One of 'null', 'name' or 'name + value' describing the content of the label.
* @constructor * @constructor
*/ */
constructor(name, visible = true, color = null, labelContent = 'name + value') { constructor(name, visible = true, color = null, labelContent = "name + value") {
if(color == null) color = getRandomColor() if(color == null) color = getRandomColor()
this.type = this.constructor.type() this.type = this.constructor.type()
this.name = name this.name = name
@ -120,7 +132,7 @@ export class DrawableObject {
export() { export() {
let exportList = [this.name, this.visible, this.color.toString(), this.labelContent] let exportList = [this.name, this.visible, this.color.toString(), this.labelContent]
for(let [name, propType] of Object.entries(this.constructor.properties())) for(let [name, propType] of Object.entries(this.constructor.properties()))
if(!name.startsWith('comment')) if(!name.startsWith("comment"))
exportList.push(serializesByPropertyType(propType, this[name])) exportList.push(serializesByPropertyType(propType, this[name]))
return exportList return exportList
} }
@ -151,12 +163,12 @@ export class DrawableObject {
*/ */
getLabel() { getLabel() {
switch(this.labelContent) { switch(this.labelContent) {
case 'name': case "name":
return this.name return this.name
case 'name + value': case "name + value":
return this.getReadableString() return this.getReadableString()
case 'null': case "null":
return '' return ""
} }
} }
@ -170,12 +182,12 @@ export class DrawableObject {
*/ */
getLatexLabel() { getLatexLabel() {
switch(this.labelContent) { switch(this.labelContent) {
case 'name': case "name":
return Latex.variable(this.name) return Latex.variable(this.name)
case 'name + value': case "name + value":
return this.getLatexString() return this.getLatexString()
case 'null': case "null":
return '' return ""
} }
} }
@ -203,8 +215,8 @@ export class DrawableObject {
let currentObjectsByName = Objects.currentObjectsByName let currentObjectsByName = Objects.currentObjectsByName
let properties = this.constructor.properties() let properties = this.constructor.properties()
for(let property in properties) for(let property in properties)
if(typeof properties[property] == 'object' && 'type' in properties[property]) if(typeof properties[property] == "object" && "type" in properties[property])
if(properties[property].type === 'Expression' && this[property] != null) { if(properties[property].type === "Expression" && this[property] != null) {
// Expressions with dependencies // Expressions with dependencies
for(let objName of this[property].requiredObjects()) { for(let objName of this[property].requiredObjects()) {
if(objName in currentObjectsByName && !this.requires.includes(currentObjectsByName[objName])) { if(objName in currentObjectsByName && !this.requires.includes(currentObjectsByName[objName])) {
@ -216,7 +228,7 @@ export class DrawableObject {
// Recalculate // Recalculate
this[property].recache() this[property].recache()
} else if(properties[property].type === 'ObjectType' && this[property] != null) { } else if(properties[property].type === "ObjectType" && this[property] != null) {
// Object dependency // Object dependency
this.requires.push(this[property]) this.requires.push(this[property])
this[property].requiredBy.push(this) this[property].requiredBy.push(this)
@ -242,7 +254,8 @@ export class DrawableObject {
* Abstract method. Draw the object onto the canvas with the. * Abstract method. Draw the object onto the canvas with the.
* @param {CanvasAPI} canvas * @param {CanvasAPI} canvas
*/ */
draw(canvas) {} draw(canvas) {
}
/** /**
* Applicates a drawFunction with two position arguments depending on * Applicates a drawFunction with two position arguments depending on
@ -252,46 +265,46 @@ export class DrawableObject {
* *
* @param {string|Enum} labelPosition - Position of the label relative to the marked 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 {number} offset - Margin between the position and the object to be drawn
* @param {Object.<string, int>} size - Size of the label item, containing two properties, "width" and "height" * @param {{width: number, height: number}} size - Size of the label item, containing two properties, "width" and "height"
* @param {number} posX - Component of the marked position on the x-axis * @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 {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 * @param {function} drawFunction - Function with two arguments (x, y) that will be called to draw the label
*/ */
drawPositionDivergence(labelPosition, offset, size, posX, posY, drawFunction) { drawPositionDivergence(labelPosition, offset, size, posX, posY, drawFunction) {
switch(labelPosition) { switch(labelPosition) {
case 'center': case "center":
drawFunction(posX-size.width/2, posY-size.height/2) drawFunction(posX - size.width / 2, posY - size.height / 2)
break; break
case 'top': case "top":
case 'above': case "above":
drawFunction(posX-size.width/2, posY-size.height-offset) drawFunction(posX - size.width / 2, posY - size.height - offset)
break; break
case 'bottom': case "bottom":
case 'below': case "below":
drawFunction(posX-size.width/2, posY+offset) drawFunction(posX - size.width / 2, posY + offset)
break; break
case 'left': case "left":
drawFunction(posX-size.width-offset, posY-size.height/2) drawFunction(posX - size.width - offset, posY - size.height / 2)
break; break
case 'right': case "right":
drawFunction(posX+offset, posY-size.height/2) drawFunction(posX + offset, posY - size.height / 2)
break; break
case 'top-left': case "top-left":
case 'above-left': case "above-left":
drawFunction(posX-size.width, posY-size.height-offset) drawFunction(posX - size.width, posY - size.height - offset)
break; break
case 'top-right': case "top-right":
case 'above-right': case "above-right":
drawFunction(posX+offset, posY-size.height-offset) drawFunction(posX + offset, posY - size.height - offset)
break; break
case 'bottom-left': case "bottom-left":
case 'below-left': case "below-left":
drawFunction(posX-size.width-offset, posY+offset) drawFunction(posX - size.width - offset, posY + offset)
break; break
case 'bottom-right': case "bottom-right":
case 'below-right': case "below-right":
drawFunction(posX+offset, posY+offset) drawFunction(posX + offset, posY + offset)
break; break
} }
} }
@ -315,7 +328,7 @@ export class DrawableObject {
* @param {function|null} drawFunctionLatex - Function (x,y,imageData) to display the latex image * @param {function|null} drawFunctionLatex - Function (x,y,imageData) to display the latex image
* @param {function|null} drawFunctionText - Function (x,y,text,textSize) to display the text * @param {function|null} drawFunctionText - Function (x,y,text,textSize) to display the text
*/ */
drawLabel(canvas, labelPosition, posX, posY,forceText = false, drawLabel(canvas, labelPosition, posX, posY, forceText = false,
getLatexFunction = null, getTextFunction = null, drawFunctionLatex = null, drawFunctionText = null) { getLatexFunction = null, getTextFunction = null, drawFunctionLatex = null, drawFunctionText = null) {
// Default functions // Default functions
if(getLatexFunction == null) if(getLatexFunction == null)
@ -323,30 +336,29 @@ export class DrawableObject {
if(getTextFunction == null) if(getTextFunction == null)
getTextFunction = this.getLabel.bind(this) getTextFunction = this.getLabel.bind(this)
if(drawFunctionLatex == null) if(drawFunctionLatex == null)
drawFunctionLatex = (x,y,ltxImg) => canvas.drawVisibleImage(ltxImg.source, x, y, ltxImg.width, ltxImg.height) drawFunctionLatex = (x, y, ltxImg) => canvas.drawVisibleImage(ltxImg.source, x, y, ltxImg.width, ltxImg.height)
if(drawFunctionText == null) if(drawFunctionText == null)
drawFunctionText = (x,y,text,textSize) => canvas.drawVisibleText(text, x, y+textSize.height) // Positioned from left bottom drawFunctionText = (x, y, text, textSize) => canvas.drawVisibleText(text, x, y + textSize.height) // Positioned from left bottom
// Drawing the label // Drawing the label
let offset
if(!forceText && Latex.enabled) { if(!forceText && Latex.enabled) {
// With latex // With latex
let drawLblCb = ((ltxImg) => { let drawLblCb = ((ltxImg) => {
this.drawPositionDivergence(labelPosition, 8+canvas.linewidth/2, ltxImg, posX, posY, (x,y) => drawFunctionLatex(x,y,ltxImg)) this.drawPositionDivergence(labelPosition, 8 + canvas.linewidth / 2, ltxImg, posX, posY, (x, y) => drawFunctionLatex(x, y, ltxImg))
}).bind(this) })
let ltxLabel = getLatexFunction(); let ltxLabel = getLatexFunction()
if(ltxLabel !== "") if(ltxLabel !== "")
canvas.renderLatexImage(ltxLabel, this.color, drawLblCb.bind(this)) canvas.renderLatexImage(ltxLabel, this.color, drawLblCb)
} else { } else {
// Without latex // Without latex
let text = getTextFunction() let text = getTextFunction()
canvas.font = `${canvas.textsize}px sans-serif` canvas.font = `${canvas.textsize}px sans-serif`
let textSize = canvas.measureText(text) let textSize = canvas.measureText(text)
this.drawPositionDivergence(labelPosition, 8+canvas.linewidth/2, textSize, posX, posY, (x,y) => drawFunctionText(x,y,text,textSize)) this.drawPositionDivergence(labelPosition, 8 + canvas.linewidth / 2, textSize, posX, posY, (x, y) => drawFunctionText(x, y, text, textSize))
} }
} }
toString() { toString() {
return this.name; return this.name
} }
} }
@ -367,28 +379,38 @@ export class ExecutableObject extends DrawableObject {
* @param {number} x * @param {number} x
* @returns {number|null} * @returns {number|null}
*/ */
execute(x = 1) {return 0} execute(x = 1) {
return 0
}
/** /**
* Returns false if the object isn't defined on the given x, true otherwise. * Returns false if the object isn't defined on the given x, true otherwise.
* *
* @param {number} x * @param {number} x
* @returns {boolean} * @returns {boolean}
*/ */
canExecute(x = 1) {return true} canExecute(x = 1) {
return true
}
/** /**
* Returns the simplified expression string for a given x. * Returns the simplified expression string for a given x.
* *
* @param {number} x * @param {number} x
* @returns {string|Expression} * @returns {string|Expression}
*/ */
simplify(x = 1) {return '0'} simplify(x = 1) {
return "0"
}
/** /**
* True if this object can be executed, so that an y value might be computed * True if this object can be executed, so that an y value might be computed
* for an x value. Only ExecutableObjects have that property set to true. * for an x value. Only ExecutableObjects have that property set to true.
* @return {boolean} * @return {boolean}
*/ */
static executable() {return true} static executable() {
return true
}
} }

View file

@ -24,18 +24,30 @@ import { ExecutableObject } from "./common.mjs"
export default class DistributionFunction extends ExecutableObject { export default class DistributionFunction extends ExecutableObject {
static type(){return 'Repartition'} static type() {
static displayType(){return qsTranslate("distribution", 'Repartition')} return "Repartition"
static displayTypeMultiple(){return qsTranslate("distribution", 'Repartition functions')} }
static properties() {return {
'comment1': QT_TRANSLATE_NOOP( static displayType() {
'comment', return qsTranslate("distribution", "Repartition")
'Note: Specify the probability for each value.' }
static displayTypeMultiple() {
return qsTranslate("distribution", "Repartition functions")
}
static properties() {
return {
"comment1": QT_TRANSLATE_NOOP(
"comment",
"Note: Specify the probability for each value."
), ),
[QT_TRANSLATE_NOOP('prop','probabilities')]: new P.Dictionary('string', 'double', /^-?[\d.,]+$/, /^-?[\d.,]+$/, 'P({name_} = ', ') = '), [QT_TRANSLATE_NOOP("prop", "probabilities")]: new P.Dictionary("string", "double", /^-?[\d.,]+$/, /^-?[\d.,]+$/, "P({name_} = ", ") = "),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position, [QT_TRANSLATE_NOOP("prop", "labelPosition")]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number', [QT_TRANSLATE_NOOP("prop", "labelX")]: "number"
}} }
}
static import(name, visible, color, labelContent, ...args) { static import(name, visible, color, labelContent, ...args) {
console.log(args, args.length) console.log(args, args.length)
if(args.length === 5) { if(args.length === 5) {
@ -46,9 +58,9 @@ export default class DistributionFunction extends ExecutableObject {
return super.import(name, visible, color, labelContent, ...args) return super.import(name, visible, color, labelContent, ...args)
} }
constructor(name = null, visible = true, color = null, labelContent = 'name + value', constructor(name = null, visible = true, color = null, labelContent = "name + value",
probabilities = {'0': '0'}, labelPosition = 'above', labelX = 1) { probabilities = { "0": "0" }, labelPosition = "above", labelX = 1) {
if(name == null) name = Objects.getNewName('XYZUVW', "F_") if(name == null) name = Objects.getNewName("XYZUVW", "F_")
super(name, visible, color, labelContent) super(name, visible, color, labelContent)
this.probabilities = probabilities this.probabilities = probabilities
this.labelPosition = labelPosition this.labelPosition = labelPosition
@ -57,27 +69,29 @@ export default class DistributionFunction extends ExecutableObject {
} }
getReadableString() { getReadableString() {
let keys = Object.keys(this.probabilities).sort((a,b) => a-b); let keys = Object.keys(this.probabilities).sort((a, b) => a - b)
let varname = this.name.substring(this.name.indexOf("_")+1) let varname = this.name.substring(this.name.indexOf("_") + 1)
return `${this.name}(x) = P(${varname} ≤ x)\n` + keys.map(idx => `P(${varname}=${idx})=${this.probabilities[idx]}`).join("; ") return `${this.name}(x) = P(${varname} ≤ x)\n` + keys.map(idx => `P(${varname}=${idx})=${this.probabilities[idx]}`).join("; ")
} }
getLatexString() { getLatexString() {
let keys = Object.keys(this.probabilities).sort((a,b) => a-b); let keys = Object.keys(this.probabilities).sort((a, b) => a - b)
let funcName = Latex.variable(this.name) let funcName = Latex.variable(this.name)
let varName = Latex.variable(this.name.substring(this.name.indexOf("_")+1)) let varName = Latex.variable(this.name.substring(this.name.indexOf("_") + 1))
return `\\begin{array}{l}{${funcName}}(x) = P(${varName} \\le x)\\\\` + keys.map(idx => `P(${varName}=${idx})=${this.probabilities[idx]}`).join("; ") + '\\end{array}' return `\\begin{array}{l}{${funcName}}(x) = P(${varName} \\le x)\\\\` + keys.map(idx => `P(${varName}=${idx})=${this.probabilities[idx]}`).join("; ") + "\\end{array}"
} }
execute(x = 1) { execute(x = 1) {
let ret = 0; let ret = 0
Object.keys(this.probabilities).sort((a,b) => a-b).forEach(idx => { Object.keys(this.probabilities).sort((a, b) => a - b).forEach(idx => {
if(x >= idx) ret += parseFloat(this.probabilities[idx].replace(/,/g, '.')) if(x >= idx) ret += parseFloat(this.probabilities[idx].replace(/,/g, "."))
}) })
return ret return ret
} }
canExecute(x = 1) {return true} canExecute(x = 1) {
return true
}
// Simplify returns the simplified string of the expression. // Simplify returns the simplified string of the expression.
simplify(x = 1) { simplify(x = 1) {
@ -86,53 +100,53 @@ export default class DistributionFunction extends ExecutableObject {
getLabel() { getLabel() {
switch(this.labelContent) { switch(this.labelContent) {
case 'name': case "name":
return `${this.name}(x)` return `${this.name}(x)`
case 'name + value': case "name + value":
return this.getReadableString() return this.getReadableString()
case 'null': case "null":
return '' return ""
} }
} }
draw(canvas) { draw(canvas) {
let currentY = 0; let currentY = 0
let keys = Object.keys(this.probabilities).map(idx => parseInt(idx)).sort((a,b) => a-b) let keys = Object.keys(this.probabilities).map(idx => parseInt(idx)).sort((a, b) => a - b)
if(canvas.isVisible(keys[0],this.probabilities[keys[0]].replace(/,/g, '.'))) { if(canvas.isVisible(keys[0], this.probabilities[keys[0]].replace(/,/g, "."))) {
canvas.drawLine(0, canvas.y2px(0), canvas.x2px(keys[0]), canvas.y2px(0)) canvas.drawLine(0, canvas.y2px(0), canvas.x2px(keys[0]), canvas.y2px(0))
if(canvas.isVisible(keys[0],0)) { if(canvas.isVisible(keys[0], 0)) {
canvas.arc(canvas.x2px(keys[0])+4,canvas.y2px(0), 4, Math.PI / 2, 3 * Math.PI / 2); canvas.arc(canvas.x2px(keys[0]) + 4, canvas.y2px(0), 4, Math.PI / 2, 3 * Math.PI / 2)
} }
} }
for(let i = 0; i < keys.length-1; i++) { for(let i = 0; i < keys.length - 1; i++) {
let idx = keys[i]; let idx = keys[i]
currentY += parseFloat(this.probabilities[idx].replace(/,/g, '.')); currentY += parseFloat(this.probabilities[idx].replace(/,/g, "."))
if(canvas.isVisible(idx,currentY) || canvas.isVisible(keys[i+1],currentY)) { if(canvas.isVisible(idx, currentY) || canvas.isVisible(keys[i + 1], currentY)) {
canvas.drawLine( canvas.drawLine(
Math.max(0,canvas.x2px(idx)), Math.max(0, canvas.x2px(idx)),
canvas.y2px(currentY), canvas.y2px(currentY),
Math.min(canvas.width,canvas.x2px(keys[i+1])), Math.min(canvas.width, canvas.x2px(keys[i + 1])),
canvas.y2px(currentY) canvas.y2px(currentY)
) )
if(canvas.isVisible(idx,currentY)) { if(canvas.isVisible(idx, currentY)) {
canvas.disc(canvas.x2px(idx), canvas.y2px(currentY), 4) canvas.disc(canvas.x2px(idx), canvas.y2px(currentY), 4)
} }
if(canvas.isVisible(keys[i+1],currentY)) { if(canvas.isVisible(keys[i + 1], currentY)) {
canvas.arc(canvas.x2px(keys[i+1])+4,canvas.y2px(currentY), 4, Math.PI / 2, 3 * Math.PI / 2); canvas.arc(canvas.x2px(keys[i + 1]) + 4, canvas.y2px(currentY), 4, Math.PI / 2, 3 * Math.PI / 2)
} }
} }
} }
if(canvas.isVisible(keys[keys.length-1],currentY+parseFloat(this.probabilities[keys[keys.length-1]]))) { if(canvas.isVisible(keys[keys.length - 1], currentY + parseFloat(this.probabilities[keys[keys.length - 1]]))) {
canvas.drawLine( canvas.drawLine(
Math.max(0,canvas.x2px(keys[keys.length-1])), Math.max(0, canvas.x2px(keys[keys.length - 1])),
canvas.y2px(currentY+parseFloat(this.probabilities[keys[keys.length-1]].replace(/,/g, '.'))), canvas.y2px(currentY + parseFloat(this.probabilities[keys[keys.length - 1]].replace(/,/g, "."))),
canvas.width, canvas.width,
canvas.y2px(currentY+parseFloat(this.probabilities[keys[keys.length-1]].replace(/,/g, '.'))) canvas.y2px(currentY + parseFloat(this.probabilities[keys[keys.length - 1]].replace(/,/g, ".")))
) )
canvas.disc( canvas.disc(
canvas.x2px(keys[keys.length-1]), canvas.x2px(keys[keys.length - 1]),
canvas.y2px( canvas.y2px(
currentY+parseFloat(this.probabilities[keys[keys.length-1]].replace(/,/g, '.')) currentY + parseFloat(this.probabilities[keys[keys.length - 1]].replace(/,/g, "."))
), ),
4 4
) )

View file

@ -25,39 +25,50 @@ import Latex from "../module/latex.mjs"
export default class Function extends ExecutableObject { export default class Function extends ExecutableObject {
static type(){return 'Function'} static type() {
static displayType(){return qsTranslate("function", 'Function')} return "Function"
static displayTypeMultiple(){return qsTranslate("function", 'Functions')} }
static properties() {return {
[QT_TRANSLATE_NOOP('prop','expression')]: new P.Expression('x'),
[QT_TRANSLATE_NOOP('prop','definitionDomain')]: 'Domain',
[QT_TRANSLATE_NOOP('prop','destinationDomain')]: 'Domain',
'comment1': QT_TRANSLATE_NOOP(
'comment',
'Ex: R+* (ℝ⁺*), N (), Z-* (ℤ⁻*), ]0;1[, {3;4;5}'
),
[QT_TRANSLATE_NOOP('prop','displayMode')]: P.Enum.FunctionDisplayType,
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
'comment2': QT_TRANSLATE_NOOP(
'comment',
'The following parameters are used when the definition domain is a non-continuous set. (Ex: , , sets like {0;3}...)'
),
[QT_TRANSLATE_NOOP('prop','drawPoints')]: 'boolean',
[QT_TRANSLATE_NOOP('prop','drawDashedLines')]: 'boolean'
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value', static displayType() {
expression = 'x', definitionDomain = 'RPE', destinationDomain = 'R', return qsTranslate("function", "Function")
displayMode = 'application', labelPosition = 'above', labelX = 1, }
static displayTypeMultiple() {
return qsTranslate("function", "Functions")
}
static properties() {
return {
[QT_TRANSLATE_NOOP("prop", "expression")]: new P.Expression("x"),
[QT_TRANSLATE_NOOP("prop", "definitionDomain")]: "Domain",
[QT_TRANSLATE_NOOP("prop", "destinationDomain")]: "Domain",
"comment1": QT_TRANSLATE_NOOP(
"comment",
"Ex: R+* (ℝ⁺*), N (), Z-* (ℤ⁻*), ]0;1[, {3;4;5}"
),
[QT_TRANSLATE_NOOP("prop", "displayMode")]: P.Enum.FunctionDisplayType,
[QT_TRANSLATE_NOOP("prop", "labelPosition")]: P.Enum.Position,
[QT_TRANSLATE_NOOP("prop", "labelX")]: "number",
"comment2": QT_TRANSLATE_NOOP(
"comment",
"The following parameters are used when the definition domain is a non-continuous set. (Ex: , , sets like {0;3}...)"
),
[QT_TRANSLATE_NOOP("prop", "drawPoints")]: "boolean",
[QT_TRANSLATE_NOOP("prop", "drawDashedLines")]: "boolean"
}
}
constructor(name = null, visible = true, color = null, labelContent = "name + value",
expression = "x", definitionDomain = "RPE", destinationDomain = "R",
displayMode = "application", labelPosition = "above", labelX = 1,
drawPoints = true, drawDashedLines = true) { drawPoints = true, drawDashedLines = true) {
if(name == null) name = Objects.getNewName('fghjqlmnopqrstuvwabcde') if(name == null) name = Objects.getNewName("fghjqlmnopqrstuvwabcde")
super(name, visible, color, labelContent) super(name, visible, color, labelContent)
if(typeof expression == 'number' || typeof expression == 'string') expression = new Expression(expression.toString()) if(typeof expression == "number" || typeof expression == "string") expression = new Expression(expression.toString())
this.expression = expression this.expression = expression
if(typeof definitionDomain == 'string') definitionDomain = parseDomain(definitionDomain) if(typeof definitionDomain == "string") definitionDomain = parseDomain(definitionDomain)
this.definitionDomain = definitionDomain this.definitionDomain = definitionDomain
if(typeof destinationDomain == 'string') destinationDomain = parseDomain(destinationDomain) if(typeof destinationDomain == "string") destinationDomain = parseDomain(destinationDomain)
this.destinationDomain = destinationDomain this.destinationDomain = destinationDomain
this.displayMode = displayMode this.displayMode = displayMode
this.labelPosition = labelPosition this.labelPosition = labelPosition
@ -67,15 +78,15 @@ export default class Function extends ExecutableObject {
} }
getReadableString() { getReadableString() {
if(this.displayMode === 'application') { if(this.displayMode === "application") {
return `${this.name}: ${this.definitionDomain}${this.destinationDomain}\n ${' '.repeat(this.name.length)}x ⟼ ${this.expression.toString()}` return `${this.name}: ${this.definitionDomain}${this.destinationDomain}\n ${" ".repeat(this.name.length)}x ⟼ ${this.expression.toString()}`
} else { } else {
return `${this.name}(x) = ${this.expression.toString()}\nD${textsub(this.name)} = ${this.definitionDomain}` return `${this.name}(x) = ${this.expression.toString()}\nD${textsub(this.name)} = ${this.definitionDomain}`
} }
} }
getLatexString() { getLatexString() {
if(this.displayMode === 'application') { if(this.displayMode === "application") {
return `${Latex.variable(this.name)}:\\begin{array}{llll}${this.definitionDomain.latexMarkup}\\textrm{ } & \\rightarrow & \\textrm{ }${this.destinationDomain.latexMarkup}\\\\ 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}` x\\textrm{ } & \\mapsto & \\textrm{ }${this.expression.latexMarkup}\\end{array}`
} else { } else {
@ -96,7 +107,7 @@ export default class Function extends ExecutableObject {
simplify(x = 1) { simplify(x = 1) {
if(this.definitionDomain.includes(x)) if(this.definitionDomain.includes(x))
return this.expression.simplify(x) return this.expression.simplify(x)
return '' return ""
} }
draw(canvas) { draw(canvas) {
@ -112,7 +123,7 @@ export default class Function extends ExecutableObject {
static drawFunction(canvas, expr, definitionDomain, destinationDomain, drawPoints = true, drawDash = true) { static drawFunction(canvas, expr, definitionDomain, destinationDomain, drawPoints = true, drawDash = true) {
let pxprecision = 10 let pxprecision = 10
let previousX = canvas.px2x(0) let previousX = canvas.px2x(0)
let previousY = null; let previousY = null
if(definitionDomain instanceof SpecialDomain && definitionDomain.moveSupported) { if(definitionDomain instanceof SpecialDomain && definitionDomain.moveSupported) {
// Point based functions. // Point based functions.
previousX = definitionDomain.next(previousX) previousX = definitionDomain.next(previousX)
@ -121,16 +132,16 @@ export default class Function extends ExecutableObject {
if(!drawPoints && !drawDash) return if(!drawPoints && !drawDash) return
while(previousX !== null && canvas.x2px(previousX) < canvas.width) { while(previousX !== null && canvas.x2px(previousX) < canvas.width) {
// Reconverted for canvas to fix for logarithmic scales. // Reconverted for canvas to fix for logarithmic scales.
let currentX = definitionDomain.next(canvas.px2x(canvas.x2px(previousX)+pxprecision)); let currentX = definitionDomain.next(canvas.px2x(canvas.x2px(previousX) + pxprecision))
let currentY = expr.execute(currentX) let currentY = expr.execute(currentX)
if(currentX === null) break; if(currentX === null) break
if((definitionDomain.includes(currentX) || definitionDomain.includes(previousX)) && if((definitionDomain.includes(currentX) || definitionDomain.includes(previousX)) &&
(destinationDomain.includes(currentY) || destinationDomain.includes(previousY))) { (destinationDomain.includes(currentY) || destinationDomain.includes(previousY))) {
if(drawDash) if(drawDash)
canvas.drawDashedLine(canvas.x2px(previousX), canvas.y2px(previousY), canvas.x2px(currentX), canvas.y2px(currentY)) canvas.drawDashedLine(canvas.x2px(previousX), canvas.y2px(previousY), canvas.x2px(currentX), canvas.y2px(currentY))
if(drawPoints) { if(drawPoints) {
canvas.fillRect(canvas.x2px(previousX)-5, canvas.y2px(previousY)-1, 10, 2) canvas.fillRect(canvas.x2px(previousX) - 5, canvas.y2px(previousY) - 1, 10, 2)
canvas.fillRect(canvas.x2px(previousX)-1, canvas.y2px(previousY)-5, 2, 10) canvas.fillRect(canvas.x2px(previousX) - 1, canvas.y2px(previousY) - 5, 2, 10)
} }
} }
previousX = currentX previousX = currentX
@ -138,8 +149,8 @@ export default class Function extends ExecutableObject {
} }
if(drawPoints) { if(drawPoints) {
// Drawing the last cross // Drawing the last cross
canvas.fillRect(canvas.x2px(previousX)-5, canvas.y2px(previousY)-1, 10, 2) canvas.fillRect(canvas.x2px(previousX) - 5, canvas.y2px(previousY) - 1, 10, 2)
canvas.fillRect(canvas.x2px(previousX)-1, canvas.y2px(previousY)-5, 2, 10) canvas.fillRect(canvas.x2px(previousX) - 1, canvas.y2px(previousY) - 5, 2, 10)
} }
} else { } else {
// Use max precision if function is trigonometrical on log scale. // Use max precision if function is trigonometrical on log scale.
@ -154,9 +165,9 @@ export default class Function extends ExecutableObject {
if(!definitionDomain.includes(previousX) && definitionDomain.includes(currentX)) { if(!definitionDomain.includes(previousX) && definitionDomain.includes(currentX)) {
// Should draw up to currentX, but NOT at previousX. // Should draw up to currentX, but NOT at previousX.
// Need to find the starting point. // Need to find the starting point.
let tmpPx = px-pxprecision let tmpPx = px - pxprecision
do { do {
tmpPx++; tmpPx++
previousX = canvas.px2x(tmpPx) previousX = canvas.px2x(tmpPx)
} while(!definitionDomain.includes(previousX)) } while(!definitionDomain.includes(previousX))
// Recaclulate previousY // Recaclulate previousY
@ -166,16 +177,16 @@ export default class Function extends ExecutableObject {
// Augmenting the pixel precision until this condition is fulfilled. // Augmenting the pixel precision until this condition is fulfilled.
let tmpPx = px let tmpPx = px
do { do {
tmpPx--; tmpPx--
currentX = canvas.px2x(tmpPx) currentX = canvas.px2x(tmpPx)
} while(!definitionDomain.includes(currentX) && currentX !== previousX) } while(!definitionDomain.includes(currentX) && currentX !== previousX)
} }
// This max variation is needed for functions with asymptotical vertical lines (e.g. 1/x, tan x...) // This max variation is needed for functions with asymptotical vertical lines (e.g. 1/x, tan x...)
let maxvariation = (canvas.px2y(0)-canvas.px2y(canvas.height)) let maxvariation = (canvas.px2y(0) - canvas.px2y(canvas.height))
if(definitionDomain.includes(previousX) && definitionDomain.includes(currentX)) { if(definitionDomain.includes(previousX) && definitionDomain.includes(currentX)) {
let currentY = expr.execute(currentX) let currentY = expr.execute(currentX)
if(destinationDomain.includes(currentY)) { if(destinationDomain.includes(currentY)) {
if(previousY != null && destinationDomain.includes(previousY) && Math.abs(previousY-currentY) < maxvariation) { if(previousY != null && destinationDomain.includes(previousY) && Math.abs(previousY - currentY) < maxvariation) {
canvas.drawLine(canvas.x2px(previousX), canvas.y2px(previousY), canvas.x2px(currentX), canvas.y2px(currentY)) canvas.drawLine(canvas.x2px(previousX), canvas.y2px(previousY), canvas.x2px(currentX), canvas.y2px(currentY))
} }
} }

View file

@ -25,24 +25,34 @@ import { DrawableObject } from "./common.mjs"
export default class Point extends DrawableObject { export default class Point extends DrawableObject {
static type(){return 'Point'} static type() {
static displayType(){return qsTranslate("point", 'Point')} return "Point"
static displayTypeMultiple(){return qsTranslate("point", 'Points')} }
static properties() {return { static displayType() {
[QT_TRANSLATE_NOOP('prop','x')]: new P.Expression(), return qsTranslate("point", "Point")
[QT_TRANSLATE_NOOP('prop','y')]: new P.Expression(), }
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','pointStyle')]: new P.Enum('●', '✕', '')
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value', static displayTypeMultiple() {
x = 1, y = 0, labelPosition = 'above', pointStyle = '●') { return qsTranslate("point", "Points")
if(name == null) name = Objects.getNewName('ABCDEFJKLMNOPQRSTUVW') }
static properties() {
return {
[QT_TRANSLATE_NOOP("prop", "x")]: new P.Expression(),
[QT_TRANSLATE_NOOP("prop", "y")]: new P.Expression(),
[QT_TRANSLATE_NOOP("prop", "labelPosition")]: P.Enum.Position,
[QT_TRANSLATE_NOOP("prop", "pointStyle")]: new P.Enum("●", "✕", "")
}
}
constructor(name = null, visible = true, color = null, labelContent = "name + value",
x = 1, y = 0, labelPosition = "above", pointStyle = "●") {
if(name == null) name = Objects.getNewName("ABCDEFJKLMNOPQRSTUVW")
super(name, visible, color, labelContent) super(name, visible, color, labelContent)
if(typeof x == 'number' || typeof x == 'string') x = new Expression(x.toString()) if(typeof x == "number" || typeof x == "string") x = new Expression(x.toString())
this.x = x this.x = x
if(typeof y == 'number' || typeof y == 'string') y = new Expression(y.toString()) if(typeof y == "number" || typeof y == "string") y = new Expression(y.toString())
this.y = y this.y = y
this.labelPosition = labelPosition this.labelPosition = labelPosition
this.pointStyle = pointStyle this.pointStyle = pointStyle
@ -58,19 +68,19 @@ export default class Point extends DrawableObject {
draw(canvas) { draw(canvas) {
let [canvasX, canvasY] = [canvas.x2px(this.x.execute()), canvas.y2px(this.y.execute())] let [canvasX, canvasY] = [canvas.x2px(this.x.execute()), canvas.y2px(this.y.execute())]
let pointSize = 8+(canvas.linewidth*2) let pointSize = 8 + (canvas.linewidth * 2)
switch(this.pointStyle) { switch(this.pointStyle) {
case '●': case "●":
canvas.disc(canvasX, canvasY, pointSize/2) canvas.disc(canvasX, canvasY, pointSize / 2)
break; break
case '✕': case "✕":
canvas.drawLine(canvasX-pointSize/2, canvasY-pointSize/2, canvasX+pointSize/2, canvasY+pointSize/2) canvas.drawLine(canvasX - pointSize / 2, canvasY - pointSize / 2, canvasX + pointSize / 2, canvasY + pointSize / 2)
canvas.drawLine(canvasX-pointSize/2, canvasY+pointSize/2, canvasX+pointSize/2, canvasY-pointSize/2) canvas.drawLine(canvasX - pointSize / 2, canvasY + pointSize / 2, canvasX + pointSize / 2, canvasY - pointSize / 2)
break; break
case '': case "":
canvas.fillRect(canvasX-pointSize/2, canvasY-1, pointSize, 2) canvas.fillRect(canvasX - pointSize / 2, canvasY - 1, pointSize, 2)
canvas.fillRect(canvasX-1, canvasY-pointSize/2, 2, pointSize) canvas.fillRect(canvasX - 1, canvasY - pointSize / 2, 2, pointSize)
break; break
} }
this.drawLabel(canvas, this.labelPosition, canvasX, canvasY) this.drawLabel(canvas, this.labelPosition, canvasX, canvasY)
} }

View file

@ -26,27 +26,37 @@ import Function from "./function.mjs"
export default class Sequence extends ExecutableObject { export default class Sequence extends ExecutableObject {
static type(){return 'Sequence'} static type() {
static displayType(){return qsTranslate("sequence", 'Sequence')} return "Sequence"
static displayTypeMultiple(){return qsTranslate("sequence", 'Sequences')} }
static properties() {return { static displayType() {
[QT_TRANSLATE_NOOP('prop','drawPoints')]: 'boolean', return qsTranslate("sequence", "Sequence")
[QT_TRANSLATE_NOOP('prop','drawDashedLines')]: 'boolean', }
[QT_TRANSLATE_NOOP('prop','defaultExpression')]: new P.Dictionary('string', 'int', /^.+$/, /^\d+$/, '{name}[n+', '] = ', true),
'comment1': QT_TRANSLATE_NOOP( static displayTypeMultiple() {
'comment', return qsTranslate("sequence", "Sequences")
'Note: Use %1[n] to refer to %1ₙ, %1[n+1] for %1ₙ₊₁...' }
static properties() {
return {
[QT_TRANSLATE_NOOP("prop", "drawPoints")]: "boolean",
[QT_TRANSLATE_NOOP("prop", "drawDashedLines")]: "boolean",
[QT_TRANSLATE_NOOP("prop", "defaultExpression")]: new P.Dictionary("string", "int", /^.+$/, /^\d+$/, "{name}[n+", "] = ", true),
"comment1": QT_TRANSLATE_NOOP(
"comment",
"Note: Use %1[n] to refer to %1ₙ, %1[n+1] for %1ₙ₊₁..."
), ),
[QT_TRANSLATE_NOOP('prop','baseValues')]: new P.Dictionary('string', 'int', /^.+$/, /^\d+$/, '{name}[', '] = '), [QT_TRANSLATE_NOOP("prop", "baseValues")]: new P.Dictionary("string", "int", /^.+$/, /^\d+$/, "{name}[", "] = "),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position, [QT_TRANSLATE_NOOP("prop", "labelPosition")]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number', [QT_TRANSLATE_NOOP("prop", "labelX")]: "number"
}} }
}
constructor(name = null, visible = true, color = null, labelContent = 'name + value', constructor(name = null, visible = true, color = null, labelContent = "name + value",
drawPoints = true, drawDashedLines = true, defaultExp = {1: "n"}, drawPoints = true, drawDashedLines = true, defaultExp = { 1: "n" },
baseValues = {0: 0}, labelPosition = 'above', labelX = 1) { baseValues = { 0: 0 }, labelPosition = "above", labelX = 1) {
if(name == null) name = Objects.getNewName('uvwPSUVWabcde') if(name == null) name = Objects.getNewName("uvwPSUVWabcde")
super(name, visible, color, labelContent) super(name, visible, color, labelContent)
this.drawPoints = drawPoints this.drawPoints = drawPoints
this.drawDashedLines = drawDashedLines this.drawDashedLines = drawDashedLines
@ -58,17 +68,17 @@ export default class Sequence extends ExecutableObject {
} }
update() { update() {
console.log('Updating sequence', this.sequence) console.log("Updating sequence", this.sequence)
super.update() super.update()
if( if(
this.sequence == null || this.baseValues !== this.sequence.baseValues || this.sequence == null || this.baseValues !== this.sequence.baseValues ||
this.sequence.name !== this.name || this.sequence.name !== this.name ||
this.sequence.expr !== Object.values(this.defaultExpression)[0] || this.sequence.expr !== Object.values(this.defaultExpression)[0] ||
this.sequence.valuePlus !== Object.keys(this.defaultExpression)[0] this.sequence.valuePlus.toString() !== Object.keys(this.defaultExpression)[0]
) )
this.sequence = new MathSequence( this.sequence = new MathSequence(
this.name, this.baseValues, this.name, this.baseValues,
Object.keys(this.defaultExpression)[0], parseFloat(Object.keys(this.defaultExpression)[0]),
Object.values(this.defaultExpression)[0] Object.values(this.defaultExpression)[0]
) )
} }
@ -86,7 +96,10 @@ export default class Sequence extends ExecutableObject {
return this.sequence.execute(x) return this.sequence.execute(x)
return null return null
} }
canExecute(x = 1) {return x%1 === 0}
canExecute(x = 1) {
return x % 1 === 0
}
// Simplify returns the simplified string of the expression. // Simplify returns the simplified string of the expression.
simplify(x = 1) { simplify(x = 1) {
@ -97,23 +110,23 @@ export default class Sequence extends ExecutableObject {
getLabel() { getLabel() {
switch(this.labelContent) { switch(this.labelContent) {
case 'name': case "name":
return `(${this.name}ₙ)` return `(${this.name}ₙ)`
case 'name + value': case "name + value":
return this.getReadableString() return this.getReadableString()
case 'null': case "null":
return '' return ""
} }
} }
getLatexLabel() { getLatexLabel() {
switch(this.labelContent) { switch(this.labelContent) {
case 'name': case "name":
return `(${Latex.variable(this.name)}_n)` return `(${Latex.variable(this.name)}_n)`
case 'name + value': case "name + value":
return this.getLatexString() return this.getLatexString()
case 'null': case "null":
return '' return ""
} }
} }

View file

@ -25,28 +25,39 @@ import { DrawableObject } from "./common.mjs"
export default class Text extends DrawableObject { export default class Text extends DrawableObject {
static type(){return 'Text'} static type() {
static displayType(){return qsTranslate("text", 'Text')} return "Text"
static displayTypeMultiple(){return qsTranslate("text", 'Texts')} }
static properties() {return {
[QT_TRANSLATE_NOOP('prop','x')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','y')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Positioning,
[QT_TRANSLATE_NOOP('prop','text')]: 'string',
'comment1': QT_TRANSLATE_NOOP(
'comment',
'If you have latex enabled, you can use use latex markup in between $$ to create equations.'
),
[QT_TRANSLATE_NOOP('prop','disableLatex')]: 'boolean'
}}
constructor(name = null, visible = true, color = null, labelContent = 'null', static displayType() {
x = 1, y = 0, labelPosition = 'center', text = 'New text', disableLatex = false) { return qsTranslate("text", "Text")
if(name == null) name = Objects.getNewName('t') }
static displayTypeMultiple() {
return qsTranslate("text", "Texts")
}
static properties() {
return {
[QT_TRANSLATE_NOOP("prop", "x")]: new P.Expression(),
[QT_TRANSLATE_NOOP("prop", "y")]: new P.Expression(),
[QT_TRANSLATE_NOOP("prop", "labelPosition")]: P.Enum.Positioning,
[QT_TRANSLATE_NOOP("prop", "text")]: "string",
"comment1": QT_TRANSLATE_NOOP(
"comment",
"If you have latex enabled, you can use use latex markup in between $$ to create equations."
),
[QT_TRANSLATE_NOOP("prop", "disableLatex")]: "boolean"
}
}
constructor(name = null, visible = true, color = null, labelContent = "null",
x = 1, y = 0, labelPosition = "center", text = "New text", disableLatex = false) {
if(name == null) name = Objects.getNewName("t")
super(name, visible, color, labelContent) super(name, visible, color, labelContent)
if(typeof x == 'number' || typeof x == 'string') x = new Expression(x.toString()) if(typeof x == "number" || typeof x == "string") x = new Expression(x.toString())
this.x = x this.x = x
if(typeof y == 'number' || typeof y == 'string') y = new Expression(y.toString()) if(typeof y == "number" || typeof y == "string") y = new Expression(y.toString())
this.y = y this.y = y
this.labelPosition = labelPosition this.labelPosition = labelPosition
this.text = text this.text = text
@ -60,15 +71,17 @@ export default class Text extends DrawableObject {
latexMarkupText() { latexMarkupText() {
// Check whether the text contains latex escaped elements. // Check whether the text contains latex escaped elements.
let txt = [] let txt = []
this.text.split('$$').forEach(function(t) { txt = txt.concat(Latex.variable(t, true).replace(/\$\$/g, '').split('$')) }) this.text.split("$$").forEach(function(t) {
txt = txt.concat(Latex.variable(t, true).replace(/\$\$/g, "").split("$"))
})
let newTxt = txt[0] let newTxt = txt[0]
let i let i
// Split between normal text and latex escaped. // Split between normal text and latex escaped.
for(i = 0; i < txt.length-1; i++) for(i = 0; i < txt.length - 1; i++)
if(i & 0x01) // Every odd number if(i & 0x01) // Every odd number
newTxt += '\\textsf{'+Latex.variable(txt[i+1]) newTxt += "\\textsf{" + Latex.variable(txt[i + 1])
else else
newTxt += '}'+txt[i+1] newTxt += "}" + txt[i + 1]
// Finished by a } // Finished by a }
if(i & 0x01) if(i & 0x01)
newTxt += "{" newTxt += "{"
@ -88,8 +101,8 @@ export default class Text extends DrawableObject {
} }
draw(canvas) { draw(canvas) {
let yOffset = this.disableLatex ? canvas.textsize-4 : 0 let yOffset = this.disableLatex ? canvas.textsize - 4 : 0
this.drawLabel(canvas, this.labelPosition, canvas.x2px(this.x.execute()), canvas.y2px(this.y.execute())+yOffset, this.disableLatex) this.drawLabel(canvas, this.labelPosition, canvas.x2px(this.x.execute()), canvas.y2px(this.y.execute()) + yOffset, this.disableLatex)
} }
} }

View file

@ -73,29 +73,28 @@ export default class XCursor extends DrawableObject {
\\end{array}` \\end{array}`
} }
getTargetValueLabel() { getApprox() {
var t = this.targetElement let approx = ''
var approx = ''
if(this.approximate) { if(this.approximate) {
approx = (t.execute(this.x.execute())) approx = (this.targetElement.execute(this.x.execute()))
let intLength = Math.round(approx).toString().length let intLength = Math.round(approx).toString().length
let rounding = Math.min(this.rounding, approx.toString().length - intLength - 1) let rounding = Math.min(this.rounding, approx.toString().length - intLength - 1)
approx = approx.toPrecision(rounding + intLength) approx = approx.toPrecision(rounding + intLength)
} }
return approx
}
getTargetValueLabel() {
const t = this.targetElement
const approx = this.getApprox()
return `${t.name}(${this.name}) = ${t.simplify(this.x.toEditableString())}` + return `${t.name}(${this.name}) = ${t.simplify(this.x.toEditableString())}` +
(this.approximate ? ' ≈ ' + approx : '') (this.approximate ? ' ≈ ' + approx : '')
} }
getTargetValueLatexLabel() { getTargetValueLatexLabel() {
let t = this.targetElement const t = this.targetElement
let approx = '' const approx = this.getApprox()
if(this.approximate) { const simpl = t.simplify(this.x.toEditableString())
approx = (t.execute(this.x.execute()))
let intLength = Math.round(approx).toString().length
let rounding = Math.min(this.rounding, approx.toString().length - intLength - 1)
approx = approx.toPrecision(rounding + intLength)
}
let simpl = t.simplify(this.x.toEditableString())
return `${Latex.variable(t.name)}(${Latex.variable(this.name)}) = ${simpl.latexMarkup ? simpl.latexMarkup : Latex.variable(simpl)}` + return `${Latex.variable(t.name)}(${Latex.variable(this.name)}) = ${simpl.latexMarkup ? simpl.latexMarkup : Latex.variable(simpl)}` +
(this.approximate ? ' \\simeq ' + approx : '') (this.approximate ? ' \\simeq ' + approx : '')
} }
@ -104,16 +103,13 @@ export default class XCursor extends DrawableObject {
switch(this.labelContent) { switch(this.labelContent) {
case 'name': case 'name':
return this.name return this.name
break;
case 'name + value': case 'name + value':
switch(this.targetValuePosition) { switch(this.targetValuePosition) {
case 'Next to target': case 'Next to target':
case 'Hidden': case 'Hidden':
return `${this.name} = ${this.x.toString()}` return `${this.name} = ${this.x.toString()}`
break;
case 'With label': case 'With label':
return this.getReadableString() return this.getReadableString()
break;
} }
case 'null': case 'null':
return '' return ''
@ -124,16 +120,13 @@ export default class XCursor extends DrawableObject {
switch(this.labelContent) { switch(this.labelContent) {
case 'name': case 'name':
return Latex.variable(this.name) return Latex.variable(this.name)
break;
case 'name + value': case 'name + value':
switch(this.targetValuePosition) { switch(this.targetValuePosition) {
case 'Next to target': case 'Next to target':
case 'Hidden': case 'Hidden':
return `${Latex.variable(this.name)} = ${this.x.latexMarkup}` return `${Latex.variable(this.name)} = ${this.x.latexMarkup}`
break;
case 'With label': case 'With label':
return this.getLatexString() return this.getLatexString()
break;
} }
case 'null': case 'null':
return '' return ''

View file

@ -15,15 +15,16 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import {parseDomain, Expression as Expr, Domain} from "./math/index.mjs" import { parseDomain, Expression as Expr, Domain } from "./math/index.mjs"
import Objects from "./module/objects.mjs" import Objects from "./module/objects.mjs"
const NONE = class Empty {} const NONE = class Empty {
}
let stringValuesValidators = { let stringValuesValidators = {
'int': [parseInt, (x) => !isNaN(x)], "int": [parseInt, (x) => !isNaN(x)],
'double': [parseFloat, (x) => !isNaN(x)], "double": [parseFloat, (x) => !isNaN(x)],
'string': [(x) => x, () => true] "string": [(x) => x, () => true]
} }
let stringValidatorTypes = Object.keys(stringValuesValidators) let stringValidatorTypes = Object.keys(stringValuesValidators)
@ -52,17 +53,17 @@ class PropertyType {
export class Expression extends PropertyType { export class Expression extends PropertyType {
constructor(...variables) { constructor(...variables) {
super() super()
this.type = 'Expression' this.type = "Expression"
this.variables = variables this.variables = variables
} }
toString() { toString() {
return this.variables.length === 0 ? 'Number' : `Expression(${this.variables.join(', ')})` return this.variables.length === 0 ? "Number" : `Expression(${this.variables.join(", ")})`
} }
parse(value) { parse(value) {
let result = NONE let result = NONE
if(typeof value == 'string') if(typeof value == "string")
try { try {
result = new Expr(value) result = new Expr(value)
} catch(e) { } catch(e) {
@ -86,14 +87,14 @@ export class Expression extends PropertyType {
export class Enum extends PropertyType { export class Enum extends PropertyType {
constructor(...values) { constructor(...values) {
super() super()
this.type = 'Enum' this.type = "Enum"
this.values = values this.values = values
this.legacyValues = {} this.legacyValues = {}
this.translatedValues = values.map(x => qsTranslate('parameters', x)) this.translatedValues = values.map(x => qsTranslate("parameters", x))
} }
toString() { toString() {
return `${this.type}(${this.values.join(', ')})` return `${this.type}(${this.values.join(", ")})`
} }
parse(value) { parse(value) {
@ -111,15 +112,15 @@ export class Enum extends PropertyType {
else if(this.legacyValues[value]) else if(this.legacyValues[value])
return this.legacyValues[value] return this.legacyValues[value]
else else
throw new TypeError(`Exportation error: ${value} not one of ${this.values.join(', ')}.`) throw new TypeError(`Exportation error: ${value} not one of ${this.values.join(", ")}.`)
} }
} }
export class ObjectType extends PropertyType { export class ObjectType extends PropertyType {
constructor(objType, allowNull=false) { constructor(objType, allowNull = false) {
super() super()
this.type = 'ObjectType' this.type = "ObjectType"
this.objType = objType this.objType = objType
this.allowNull = allowNull this.allowNull = allowNull
} }
@ -130,9 +131,9 @@ export class ObjectType extends PropertyType {
parse(name) { parse(name) {
let result = NONE let result = NONE
if(typeof name == 'string' && name in Objects.currentObjectsByName) { if(typeof name == "string" && name in Objects.currentObjectsByName) {
let obj = Objects.currentObjectsByName[name] let obj = Objects.currentObjectsByName[name]
if (obj.type === this.objType || (this.objType === 'ExecutableObject' && obj.execute)) { if(obj.type === this.objType || (this.objType === "ExecutableObject" && obj.execute)) {
result = obj result = obj
} else { } else {
// Silently error and return null // Silently error and return null
@ -147,7 +148,7 @@ export class ObjectType extends PropertyType {
export(value) { export(value) {
if(value == null && this.allowNull) if(value == null && this.allowNull)
return null return null
else if(value.type === this.objType || (this.objType === 'ExecutableObject' && value.execute)) else if(value.type === this.objType || (this.objType === "ExecutableObject" && value.execute))
return value.name return value.name
else else
throw new TypeError(`Exportation error: ${value} not a ${this.objType}.`) throw new TypeError(`Exportation error: ${value} not a ${this.objType}.`)
@ -156,13 +157,13 @@ export class ObjectType extends PropertyType {
export class List extends PropertyType { export class List extends PropertyType {
constructor(type, format = /^.+$/, label = '', forbidAdding = false) { constructor(type, format = /^.+$/, label = "", forbidAdding = false) {
super() super()
// type can be string, int and double. // type can be string, int and double.
this.type = 'List' this.type = "List"
this.valueType = type this.valueType = type
if(!stringValidatorTypes.includes(this.valueType)) if(!stringValidatorTypes.includes(this.valueType))
throw new TypeError(`${this.valueType} must be one of ${stringValidatorTypes.join(', ')}.`) throw new TypeError(`${this.valueType} must be one of ${stringValidatorTypes.join(", ")}.`)
this.format = format this.format = format
this.label = label this.label = label
this.forbidAdding = forbidAdding this.forbidAdding = forbidAdding
@ -174,10 +175,10 @@ export class List extends PropertyType {
parse(value) { parse(value) {
let result = NONE let result = NONE
if(typeof value == 'object' && value.__proto__ === Array) { if(typeof value == "object" && value.__proto__ === Array) {
let valid = 0 let valid = 0
for(let v of value) { for(let v of value) {
if (this.format.test(v)) { if(this.format.test(v)) {
v = stringValuesValidators[this.valueType][0](v) v = stringValuesValidators[this.valueType][0](v)
if(stringValuesValidators[this.valueType][1](v)) if(stringValuesValidators[this.valueType][1](v))
valid++ valid++
@ -190,7 +191,7 @@ export class List extends PropertyType {
} }
export(value) { export(value) {
if(typeof value == 'object' && value.__proto__ === Array) if(typeof value == "object" && value.__proto__ === Array)
return value return value
else else
throw new TypeError(`Exportation error: ${value} not a list.`) throw new TypeError(`Exportation error: ${value} not a list.`)
@ -200,10 +201,10 @@ export class List extends PropertyType {
export class Dictionary extends PropertyType { export class Dictionary extends PropertyType {
constructor(type, keyType = 'string', format = /^.+$/, keyFormat = /^.+$/, preKeyLabel = '', postKeyLabel = ': ', forbidAdding = false) { constructor(type, keyType = "string", format = /^.+$/, keyFormat = /^.+$/, preKeyLabel = "", postKeyLabel = ": ", forbidAdding = false) {
super() super()
// type & keyType can be string, int and double. // type & keyType can be string, int and double.
this.type = 'Dict' this.type = "Dict"
this.valueType = type this.valueType = type
this.keyType = keyType this.keyType = keyType
this.format = format this.format = format
@ -219,10 +220,10 @@ export class Dictionary extends PropertyType {
parse(value) { parse(value) {
let result = NONE let result = NONE
if(typeof value == 'object' && value.__proto__ !== Array) { if(typeof value == "object" && value.__proto__ !== Array) {
let dict = [] let dict = []
for(let [k, v] of Object.entries(value)) { for(let [k, v] of Object.entries(value)) {
if (this.format.test(v) && this.keyFormat.test(k)) { if(this.format.test(v) && this.keyFormat.test(k)) {
k = stringValuesValidators[this.keyType][0](k) k = stringValuesValidators[this.keyType][0](k)
v = stringValuesValidators[this.valueType][0](v) v = stringValuesValidators[this.valueType][0](v)
if(stringValuesValidators[this.keyType][1](k)) if(stringValuesValidators[this.keyType][1](k))
@ -237,7 +238,7 @@ export class Dictionary extends PropertyType {
} }
export(value) { export(value) {
if(typeof value == 'object' && value.__proto__ !== Array) if(typeof value == "object" && value.__proto__ !== Array)
return value return value
else else
throw new TypeError(`Exportation error: ${value} not a dictionary.`) throw new TypeError(`Exportation error: ${value} not a dictionary.`)
@ -247,51 +248,51 @@ export class Dictionary extends PropertyType {
// Common parameters for Enums // Common parameters for Enums
Enum.Position = new Enum( Enum.Position = new Enum(
QT_TRANSLATE_NOOP('parameters', 'above'), QT_TRANSLATE_NOOP("parameters", "above"),
QT_TRANSLATE_NOOP('parameters', 'below'), QT_TRANSLATE_NOOP("parameters", "below"),
QT_TRANSLATE_NOOP('parameters', 'left'), QT_TRANSLATE_NOOP("parameters", "left"),
QT_TRANSLATE_NOOP('parameters', 'right'), QT_TRANSLATE_NOOP("parameters", "right"),
QT_TRANSLATE_NOOP('parameters', 'above-left'), QT_TRANSLATE_NOOP("parameters", "above-left"),
QT_TRANSLATE_NOOP('parameters', 'above-right'), QT_TRANSLATE_NOOP("parameters", "above-right"),
QT_TRANSLATE_NOOP('parameters', 'below-left'), QT_TRANSLATE_NOOP("parameters", "below-left"),
QT_TRANSLATE_NOOP('parameters', 'below-right') QT_TRANSLATE_NOOP("parameters", "below-right")
) )
Enum.Position.legacyValues = { Enum.Position.legacyValues = {
'top': 'above', "top": "above",
'bottom': 'below', "bottom": "below",
'top-left': 'above-left', "top-left": "above-left",
'top-right': 'above-right', "top-right": "above-right",
'bottom-left': 'below-left', "bottom-left": "below-left",
'bottom-right': 'below-right', "bottom-right": "below-right"
} }
Enum.Positioning = new Enum( Enum.Positioning = new Enum(
QT_TRANSLATE_NOOP('parameters', 'center'), QT_TRANSLATE_NOOP("parameters", "center"),
QT_TRANSLATE_NOOP('parameters', 'top'), QT_TRANSLATE_NOOP("parameters", "top"),
QT_TRANSLATE_NOOP('parameters', 'bottom'), QT_TRANSLATE_NOOP("parameters", "bottom"),
QT_TRANSLATE_NOOP('parameters', 'left'), QT_TRANSLATE_NOOP("parameters", "left"),
QT_TRANSLATE_NOOP('parameters', 'right'), QT_TRANSLATE_NOOP("parameters", "right"),
QT_TRANSLATE_NOOP('parameters', 'top-left'), QT_TRANSLATE_NOOP("parameters", "top-left"),
QT_TRANSLATE_NOOP('parameters', 'top-right'), QT_TRANSLATE_NOOP("parameters", "top-right"),
QT_TRANSLATE_NOOP('parameters', 'bottom-left'), QT_TRANSLATE_NOOP("parameters", "bottom-left"),
QT_TRANSLATE_NOOP('parameters', 'bottom-right') QT_TRANSLATE_NOOP("parameters", "bottom-right")
) )
Enum.FunctionDisplayType = new Enum( Enum.FunctionDisplayType = new Enum(
QT_TRANSLATE_NOOP('parameters', 'application'), QT_TRANSLATE_NOOP("parameters", "application"),
QT_TRANSLATE_NOOP('parameters', 'function') QT_TRANSLATE_NOOP("parameters", "function")
) )
Enum.BodePass = new Enum( Enum.BodePass = new Enum(
QT_TRANSLATE_NOOP('parameters', 'high'), QT_TRANSLATE_NOOP("parameters", "high"),
QT_TRANSLATE_NOOP('parameters', 'low') QT_TRANSLATE_NOOP("parameters", "low")
) )
Enum.XCursorValuePosition = new Enum( Enum.XCursorValuePosition = new Enum(
QT_TRANSLATE_NOOP('parameters', 'Next to target'), QT_TRANSLATE_NOOP("parameters", "Next to target"),
QT_TRANSLATE_NOOP('parameters', 'With label'), QT_TRANSLATE_NOOP("parameters", "With label"),
QT_TRANSLATE_NOOP('parameters', 'Hidden') QT_TRANSLATE_NOOP("parameters", "Hidden")
) )
/** /**
@ -303,23 +304,23 @@ Enum.XCursorValuePosition = new Enum(
export function ensureTypeSafety(propertyType, value) { export function ensureTypeSafety(propertyType, value) {
let result let result
let error = false let error = false
if(typeof propertyType == 'string') if(typeof propertyType == "string")
switch(propertyType) { switch(propertyType) {
case 'string': case "string":
result = value result = value
error = typeof value !== 'string' error = typeof value !== "string"
break break
case 'number': case "number":
result = parseFloat(value) result = parseFloat(value)
error = isNaN(result) error = isNaN(result)
break break
case 'boolean': case "boolean":
result = value result = value
error = value !== true && value !== false error = value !== true && value !== false
break break
case 'Domain': case "Domain":
try { try {
error = typeof value !== 'string' error = typeof value !== "string"
if(!error) if(!error)
result = parseDomain(value) result = parseDomain(value)
} catch(e) { } catch(e) {
@ -353,18 +354,18 @@ export function ensureTypeSafety(propertyType, value) {
*/ */
export function serializesByPropertyType(propertyType, value) { export function serializesByPropertyType(propertyType, value) {
let result let result
if(typeof propertyType == 'string') if(typeof propertyType == "string")
switch(propertyType) { switch(propertyType) {
case 'string': case "string":
result = value.toString() result = value.toString()
break break
case 'number': case "number":
result = parseFloat(value) result = parseFloat(value)
break break
case 'boolean': case "boolean":
result = value === true result = value === true
break break
case 'Domain': case "Domain":
if(value instanceof Domain) if(value instanceof Domain)
result = value.toString() result = value.toString()
else else

View file

@ -19,28 +19,28 @@
export default class InputExpression { export default class InputExpression {
constructor(expression) { constructor(expression) {
this.position = 0; this.position = 0
this.input = expression; this.input = expression
} }
next() { next() {
return this.input[this.position++]; return this.input[this.position++]
} }
peek() { peek() {
return this.input[this.position]; return this.input[this.position]
} }
skip(char) { skip(char) {
if(!this.atEnd() && this.peek() === char) { if(!this.atEnd() && this.peek() === char) {
this.position++; this.position++
} else { } else {
this.raise("Unexpected character " + this.peek() + ". Expected character " + char); this.raise("Unexpected character " + this.peek() + ". Expected character " + char)
} }
} }
atEnd() { atEnd() {
return this.position >= this.input.length; return this.position >= this.input.length
} }
raise(message) { raise(message) {

View file

@ -25,8 +25,8 @@ export const CONSTANTS = {
"infinity": Infinity, "infinity": Infinity,
"∞": Infinity, "∞": Infinity,
"e": Math.E "e": Math.E
}; }
export const CONSTANTS_LIST = Object.keys(CONSTANTS); export const CONSTANTS_LIST = Object.keys(CONSTANTS)
export const FUNCTIONS = { export const FUNCTIONS = {
// The functions commented are the one either not implemented // The functions commented are the one either not implemented
@ -36,66 +36,66 @@ export const FUNCTIONS = {
//'-': (x) => -x, //'-': (x) => -x,
//'!' //'!'
// Other operations // Other operations
'length': (s) => Array.isArray(s) ? s.length : String(s).length, "length": (s) => Array.isArray(s) ? s.length : String(s).length,
// Boolean functions // Boolean functions
'not': (x) => !x, "not": (x) => !x,
// Math functions // Math functions
'abs': Math.abs, "abs": Math.abs,
'acos': Math.acos, "acos": Math.acos,
'acosh': Math.acosh, "acosh": Math.acosh,
'asin': Math.asin, "asin": Math.asin,
'asinh': Math.asinh, "asinh": Math.asinh,
'atan': Math.atan, "atan": Math.atan,
'atan2': Math.atan2, "atan2": Math.atan2,
'atanh': Math.atanh, "atanh": Math.atanh,
'cbrt': Math.cbrt, "cbrt": Math.cbrt,
'ceil': Math.ceil, "ceil": Math.ceil,
//'clz32': Math.clz32, //'clz32': Math.clz32,
'cos': Math.cos, "cos": Math.cos,
'cosh': Math.cosh, "cosh": Math.cosh,
'exp': Math.exp, "exp": Math.exp,
'expm1': Math.expm1, "expm1": Math.expm1,
'floor': Math.floor, "floor": Math.floor,
//'fround': Math.fround, //'fround': Math.fround,
'hypot': Math.hypot, "hypot": Math.hypot,
//'imul': Math.imul, //'imul': Math.imul,
'lg': Math.log10, "lg": Math.log10,
'ln': Math.log, "ln": Math.log,
'log': Math.log, "log": Math.log,
'log10': Math.log10, "log10": Math.log10,
'log1p': Math.log1p, "log1p": Math.log1p,
'log2': Math.log2, "log2": Math.log2,
'max': Math.max, "max": Math.max,
'min': Math.min, "min": Math.min,
'pow': Math.log2, "pow": Math.log2,
'random': Math.random, "random": Math.random,
'round': Math.round, "round": Math.round,
'sign': Math.sign, "sign": Math.sign,
'sin': Math.sin, "sin": Math.sin,
'sinh': Math.sinh, "sinh": Math.sinh,
'sqrt': Math.sqrt, "sqrt": Math.sqrt,
'tan': Math.tan, "tan": Math.tan,
'tanh': Math.tanh, "tanh": Math.tanh,
'trunc': Math.trunc, "trunc": Math.trunc,
// Functions in expr-eval, ported here. // Functions in expr-eval, ported here.
'fac': Polyfill.factorial, "fac": Polyfill.factorial,
'gamma': Polyfill.gamma, "gamma": Polyfill.gamma,
'Γ': Polyfill.gamma, "Γ": Polyfill.gamma,
'roundTo': (x, exp) => Number(x).toFixed(exp), "roundTo": (x, exp) => Number(x).toFixed(exp),
// 'map': Polyfill.arrayMap, // 'map': Polyfill.arrayMap,
// 'fold': Polyfill.arrayFold, // 'fold': Polyfill.arrayFold,
// 'filter': Polyfill.arrayFilter, // 'filter': Polyfill.arrayFilter,
// 'indexOf': Polyfill.indexOf, // 'indexOf': Polyfill.indexOf,
// 'join': Polyfill.arrayJoin, // 'join': Polyfill.arrayJoin,
// Integral & derivative (only here for autocomplete). // Integral & derivative (only here for autocomplete).
'integral': () => 0, // TODO: Implement "integral": () => 0, // TODO: Implement
'derivative': () => 0, "derivative": () => 0
} }
export const FUNCTIONS_LIST = Object.keys(FUNCTIONS); export const FUNCTIONS_LIST = Object.keys(FUNCTIONS)
export class P { export class P {
// Parameter class. // Parameter class.
constructor(type, name = '', optional = false, multipleAllowed = false) { constructor(type, name = "", optional = false, multipleAllowed = false) {
this.name = name this.name = name
this.type = type this.type = type
this.optional = optional this.optional = optional
@ -104,10 +104,10 @@ export class P {
toString() { toString() {
let base_string = this.type let base_string = this.type
if(this.name !== '') if(this.name !== "")
base_string = `${this.name}: ${base_string}` base_string = `${this.name}: ${base_string}`
if(this.multipleAllowed) if(this.multipleAllowed)
base_string += '...' base_string += "..."
if(!this.optional) if(!this.optional)
base_string = `<${base_string}>` base_string = `<${base_string}>`
else else
@ -116,59 +116,59 @@ export class P {
} }
} }
export let string = new P('string') export let string = new P("string")
export let bool = new P('bool') export let bool = new P("bool")
export let number = new P('number') export let number = new P("number")
export let array = new P('array') export let array = new P("array")
export const FUNCTIONS_USAGE = { export const FUNCTIONS_USAGE = {
'length': [string], "length": [string],
'not': [bool], "not": [bool],
// Math functions // Math functions
'abs': [number], "abs": [number],
'acos': [number], "acos": [number],
'acosh': [number], "acosh": [number],
'asin': [number], "asin": [number],
'asinh': [number], "asinh": [number],
'atan': [number], "atan": [number],
'atan2': [number], "atan2": [number],
'atanh': [number], "atanh": [number],
'cbrt': [number], "cbrt": [number],
'ceil': [number], "ceil": [number],
//'clz32': [number], //'clz32': [number],
'cos': [number], "cos": [number],
'cosh': [number], "cosh": [number],
'exp': [number], "exp": [number],
'expm1': [number], "expm1": [number],
'floor': [number], "floor": [number],
//'fround': [number], //'fround': [number],
'hypot': [number], "hypot": [number],
//'imul': [number], //'imul': [number],
'lg': [number], "lg": [number],
'ln': [number], "ln": [number],
'log': [number], "log": [number],
'log10': [number], "log10": [number],
'log1p': [number], "log1p": [number],
'log2': [number], "log2": [number],
'max': [number, number, new P('numbers', '', true, true)], "max": [number, number, new P("numbers", "", true, true)],
'min': [number, number, new P('numbers', '', true, true)], "min": [number, number, new P("numbers", "", true, true)],
'pow': [number, new P('number', 'exp')], "pow": [number, new P("number", "exp")],
'random': [number, number], "random": [number, number],
'round': [number], "round": [number],
'sign': [number], "sign": [number],
'sin': [number], "sin": [number],
'sinh': [number], "sinh": [number],
'sqrt': [number], "sqrt": [number],
'tan': [number], "tan": [number],
'tanh': [number], "tanh": [number],
'trunc': [number], "trunc": [number],
// Functions in expr-eval, ported here. // Functions in expr-eval, ported here.
'fac': [number], "fac": [number],
'gamma': [number], "gamma": [number],
'Γ': [number], "Γ": [number],
'roundTo': [number, new P('number')], "roundTo": [number, new P("number")],
// Function manipulation // Function manipulation
'derivative': [new P('f'), new P('string', 'var', true), number], "derivative": [new P("f"), new P("string", "var", true), number],
'integral': [new P('from'), new P('to'), new P('f'), new P('string', 'var', true)], "integral": [new P("from"), new P("to"), new P("f"), new P("string", "var", true)]
} }

View file

@ -20,9 +20,9 @@
import * as Reference from "./reference.mjs" import * as Reference from "./reference.mjs"
const WHITESPACES = " \t\n\r" const WHITESPACES = " \t\n\r"
const STRING_LIMITERS = '"\'`'; const STRING_LIMITERS = "\"'`"
const OPERATORS = "+-*/^%?:=!><"; const OPERATORS = "+-*/^%?:=!><"
const PUNCTUATION = "()[]{},."; const PUNCTUATION = "()[]{},."
const NUMBER_CHARS = "0123456789" const NUMBER_CHARS = "0123456789"
const IDENTIFIER_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789_₀₁₂₃₄₅₆₇₈₉αβγδεζηθκλμξρςστφχψωₐₑₒₓₔₕₖₗₘₙₚₛₜ" const IDENTIFIER_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789_₀₁₂₃₄₅₆₇₈₉αβγδεζηθκλμξρςστφχψωₐₑₒₓₔₕₖₗₘₙₚₛₜ"
@ -41,8 +41,8 @@ export const TokenType = {
export class Token { export class Token {
constructor(type, value, startPosition) { constructor(type, value, startPosition) {
this.type = type; this.type = type
this.value = value; this.value = value
this.startPosition = startPosition this.startPosition = startPosition
} }
} }
@ -55,38 +55,38 @@ export class ExpressionTokenizer {
* @param {boolean} errorOnUnknown * @param {boolean} errorOnUnknown
*/ */
constructor(input, tokenizeWhitespaces = false, errorOnUnknown = true) { constructor(input, tokenizeWhitespaces = false, errorOnUnknown = true) {
this.input = input; this.input = input
this.currentToken = null; this.currentToken = null
this.tokenizeWhitespaces = tokenizeWhitespaces this.tokenizeWhitespaces = tokenizeWhitespaces
this.errorOnUnknown = errorOnUnknown this.errorOnUnknown = errorOnUnknown
} }
skipWhitespaces() { skipWhitespaces() {
while(!this.input.atEnd() && WHITESPACES.includes(this.input.peek())) while(!this.input.atEnd() && WHITESPACES.includes(this.input.peek()))
this.input.next(); this.input.next()
} }
readWhitespaces() { readWhitespaces() {
let included = ""; let included = ""
while(!this.input.atEnd() && WHITESPACES.includes(this.input.peek())) { while(!this.input.atEnd() && WHITESPACES.includes(this.input.peek())) {
included += this.input.next(); included += this.input.next()
} }
return new Token(TokenType.WHITESPACE, included, this.input.position-included.length) return new Token(TokenType.WHITESPACE, included, this.input.position - included.length)
} }
readString() { readString() {
let delimitation = this.input.peek(); let delimitation = this.input.peek()
if(STRING_LIMITERS.includes(delimitation)) { if(STRING_LIMITERS.includes(delimitation)) {
this.input.skip(delimitation) this.input.skip(delimitation)
let included = ""; let included = ""
let justEscaped = false; let justEscaped = false
while(!this.input.atEnd() && (!STRING_LIMITERS.includes(this.input.peek()) || justEscaped)) { while(!this.input.atEnd() && (!STRING_LIMITERS.includes(this.input.peek()) || justEscaped)) {
justEscaped = this.input.peek() === "\\" justEscaped = this.input.peek() === "\\"
if(!justEscaped) if(!justEscaped)
included += this.input.next(); included += this.input.next()
} }
this.input.skip(delimitation) this.input.skip(delimitation)
let token = new Token(TokenType.STRING, included, this.input.position-included.length) let token = new Token(TokenType.STRING, included, this.input.position - included.length)
token.limitator = delimitation token.limitator = delimitation
return token return token
} else { } else {
@ -95,80 +95,80 @@ export class ExpressionTokenizer {
} }
readNumber() { readNumber() {
let included = ""; let included = ""
let hasDot = false; let hasDot = false
while(!this.input.atEnd() && (NUMBER_CHARS.includes(this.input.peek()) || this.input.peek() === '.')) { while(!this.input.atEnd() && (NUMBER_CHARS.includes(this.input.peek()) || this.input.peek() === ".")) {
if(this.input.peek() === ".") { if(this.input.peek() === ".") {
if(hasDot) this.input.raise("Unexpected '.'. Expected digit") if(hasDot) this.input.raise("Unexpected '.'. Expected digit")
hasDot = true; hasDot = true
} }
included += this.input.next(); included += this.input.next()
} }
return new Token(TokenType.NUMBER, included, this.input.position-included.length) return new Token(TokenType.NUMBER, included, this.input.position - included.length)
} }
readOperator() { readOperator() {
let included = ""; let included = ""
while(!this.input.atEnd() && OPERATORS.includes(this.input.peek())) { while(!this.input.atEnd() && OPERATORS.includes(this.input.peek())) {
included += this.input.next(); included += this.input.next()
} }
return new Token(TokenType.OPERATOR, included, this.input.position-included.length) return new Token(TokenType.OPERATOR, included, this.input.position - included.length)
} }
readIdentifier() { readIdentifier() {
let identifier = ""; let identifier = ""
while(!this.input.atEnd() && IDENTIFIER_CHARS.includes(this.input.peek().toLowerCase())) { while(!this.input.atEnd() && IDENTIFIER_CHARS.includes(this.input.peek().toLowerCase())) {
identifier += this.input.next(); identifier += this.input.next()
} }
if(Reference.CONSTANTS_LIST.includes(identifier.toLowerCase())) { if(Reference.CONSTANTS_LIST.includes(identifier.toLowerCase())) {
return new Token(TokenType.CONSTANT, identifier.toLowerCase(), this.input.position-identifier.length) return new Token(TokenType.CONSTANT, identifier.toLowerCase(), this.input.position - identifier.length)
} else if(Reference.FUNCTIONS_LIST.includes(identifier.toLowerCase())) { } else if(Reference.FUNCTIONS_LIST.includes(identifier.toLowerCase())) {
return new Token(TokenType.FUNCTION, identifier.toLowerCase(), this.input.position-identifier.length) return new Token(TokenType.FUNCTION, identifier.toLowerCase(), this.input.position - identifier.length)
} else { } else {
return new Token(TokenType.VARIABLE, identifier, this.input.position-identifier.length) return new Token(TokenType.VARIABLE, identifier, this.input.position - identifier.length)
} }
} }
readNextToken() { readNextToken() {
if(!this.tokenizeWhitespaces) if(!this.tokenizeWhitespaces)
this.skipWhitespaces() this.skipWhitespaces()
if(this.input.atEnd()) return null; if(this.input.atEnd()) return null
let c = this.input.peek(); let c = this.input.peek()
if(this.tokenizeWhitespaces && WHITESPACES.includes(c)) return this.readWhitespaces(); if(this.tokenizeWhitespaces && WHITESPACES.includes(c)) return this.readWhitespaces()
if(STRING_LIMITERS.includes(c)) return this.readString(); if(STRING_LIMITERS.includes(c)) return this.readString()
if(NUMBER_CHARS.includes(c)) return this.readNumber(); if(NUMBER_CHARS.includes(c)) return this.readNumber()
if(IDENTIFIER_CHARS.includes(c.toLowerCase())) return this.readIdentifier(); if(IDENTIFIER_CHARS.includes(c.toLowerCase())) return this.readIdentifier()
if(OPERATORS.includes(c)) return this.readOperator(); if(OPERATORS.includes(c)) return this.readOperator()
if(Reference.CONSTANTS_LIST.includes(c)) return new Token(TokenType.CONSTANT, this.input.next(), this.input.position-1); if(Reference.CONSTANTS_LIST.includes(c)) return new Token(TokenType.CONSTANT, this.input.next(), this.input.position - 1)
if(PUNCTUATION.includes(c)) return new Token(TokenType.PUNCT, this.input.next(), this.input.position-1); if(PUNCTUATION.includes(c)) return new Token(TokenType.PUNCT, this.input.next(), this.input.position - 1)
if(this.errorOnUnknown) if(this.errorOnUnknown)
this.input.raise("Unknown token character " + c) this.input.raise("Unknown token character " + c)
else else
return new Token(TokenType.UNKNOWN, this.input.next(), this.input.position-1); return new Token(TokenType.UNKNOWN, this.input.next(), this.input.position - 1)
} }
peek() { peek() {
if(this.currentToken == null) this.currentToken = this.readNextToken(); if(this.currentToken == null) this.currentToken = this.readNextToken()
return this.currentToken; return this.currentToken
} }
next() { next() {
let tmp; let tmp
if(this.currentToken == null) if(this.currentToken == null)
tmp = this.readNextToken(); tmp = this.readNextToken()
else else
tmp = this.currentToken; tmp = this.currentToken
this.currentToken = null; this.currentToken = null
return tmp; return tmp
} }
atEnd() { atEnd() {
return this.peek() == null; return this.peek() == null
} }
skip(type) { skip(type) {
let next = this.next(); let next = this.next()
if(next.type !== type) if(next.type !== type)
this.input.raise("Unexpected token " + next.type.toLowerCase() + ' "' + next.value + '". Expected ' + type.toLowerCase()); this.input.raise("Unexpected token " + next.type.toLowerCase() + " \"" + next.value + "\". Expected " + type.toLowerCase())
} }
} }

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import {Expression} from "../math/index.mjs" import { Expression } from "../math/index.mjs"
class Setting { class Setting {
constructor(type, name, nameInConfig, icon) { constructor(type, name, nameInConfig, icon) {
@ -49,7 +49,7 @@ class Setting {
export class BoolSetting extends Setting { export class BoolSetting extends Setting {
constructor(name, nameInConfig, icon) { constructor(name, nameInConfig, icon) {
super('bool', name, nameInConfig, icon) super("bool", name, nameInConfig, icon)
} }
value() { value() {
@ -63,9 +63,9 @@ export class BoolSetting extends Setting {
export class NumberSetting extends Setting { export class NumberSetting extends Setting {
constructor(name, nameInConfig, icon, min = -Infinity, max = +Infinity) { constructor(name, nameInConfig, icon, min = -Infinity, max = +Infinity) {
super('number', name, nameInConfig, icon) super("number", name, nameInConfig, icon)
this.min = typeof min == 'number' ? () => min : min this.min = typeof min == "number" ? () => min : min
this.max = typeof max == 'number' ? () => max : max this.max = typeof max == "number" ? () => max : max
} }
value() { value() {
@ -79,7 +79,7 @@ export class NumberSetting extends Setting {
export class EnumIntSetting extends Setting { export class EnumIntSetting extends Setting {
constructor(name, nameInConfig, icon, values = []) { constructor(name, nameInConfig, icon, values = []) {
super('enum', name, nameInConfig, icon) super("enum", name, nameInConfig, icon)
this.values = values this.values = values
} }
@ -94,7 +94,7 @@ export class EnumIntSetting extends Setting {
export class ExpressionSetting extends Setting { export class ExpressionSetting extends Setting {
constructor(name, nameInConfig, icon, variables = []) { constructor(name, nameInConfig, icon, variables = []) {
super('expression', name, nameInConfig, icon) super("expression", name, nameInConfig, icon)
this.variables = variables this.variables = variables
} }
@ -112,17 +112,17 @@ export class ExpressionSetting extends Setting {
Helper.setSetting(this.nameInConfig, value) Helper.setSetting(this.nameInConfig, value)
else { else {
let undefinedVars = vars.filter(x => !this.variables.includes(x)) let undefinedVars = vars.filter(x => !this.variables.includes(x))
let allowed = '' let allowed = ""
if(this.variables.length > 0) if(this.variables.length > 0)
allowed = `Allowed variables: ${this.variables.join(', ')}.` allowed = `Allowed variables: ${this.variables.join(", ")}.`
throw new TypeError(`Cannot use variable(s) ${undefinedVars.join(', or ')} to define ${this.displayName}. ${allowed}`) throw new TypeError(`Cannot use variable(s) ${undefinedVars.join(", or ")} to define ${this.displayName}. ${allowed}`)
} }
} }
} }
export class StringSetting extends Setting { export class StringSetting extends Setting {
constructor(name, nameInConfig, icon, defaultValues = []) { constructor(name, nameInConfig, icon, defaultValues = []) {
super('string', name, nameInConfig, icon) super("string", name, nameInConfig, icon)
this.defaultValues = defaultValues this.defaultValues = defaultValues
} }

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import {BoolSetting, ExpressionSetting, NumberSetting, StringSetting} from "./common.mjs" import { BoolSetting, ExpressionSetting, NumberSetting, StringSetting } from "./common.mjs"
const XZOOM = new NumberSetting( const XZOOM = new NumberSetting(
@ -49,13 +49,13 @@ const YMAX = new NumberSetting(
const XAXISSTEP = new ExpressionSetting( const XAXISSTEP = new ExpressionSetting(
qsTranslate("Settings", "X Axis Step"), qsTranslate("Settings", "X Axis Step"),
"default_graph.xaxisstep", "default_graph.xaxisstep",
"xaxisstep", "xaxisstep"
) )
const YAXISSTEP = new ExpressionSetting( const YAXISSTEP = new ExpressionSetting(
qsTranslate("Settings", "Y Axis Step"), qsTranslate("Settings", "Y Axis Step"),
"default_graph.yaxisstep", "default_graph.yaxisstep",
"yaxisstep", "yaxisstep"
) )
const LINE_WIDTH = new NumberSetting( const LINE_WIDTH = new NumberSetting(
@ -72,33 +72,33 @@ const TEXT_SIZE = new NumberSetting(
) )
const X_LABEL = new StringSetting( const X_LABEL = new StringSetting(
qsTranslate("Settings", 'X Label'), qsTranslate("Settings", "X Label"),
"default_graph.xlabel", "default_graph.xlabel",
"xlabel", "xlabel",
["", "x", "ω (rad/s)"] ["", "x", "ω (rad/s)"]
) )
const Y_LABEL = new StringSetting( const Y_LABEL = new StringSetting(
qsTranslate("Settings", 'Y Label'), qsTranslate("Settings", "Y Label"),
"default_graph.ylabel", "default_graph.ylabel",
"xlabel", "xlabel",
["", "y", "G (dB)", "φ (°)", "φ (deg)", "φ (rad)"] ["", "y", "G (dB)", "φ (°)", "φ (deg)", "φ (rad)"]
) )
const LOG_SCALE_X = new BoolSetting( const LOG_SCALE_X = new BoolSetting(
qsTranslate("Settings", 'X Log scale'), qsTranslate("Settings", "X Log scale"),
"default_graph.logscalex", "default_graph.logscalex",
"logscalex" "logscalex"
) )
const SHOW_X_GRAD = new BoolSetting( const SHOW_X_GRAD = new BoolSetting(
qsTranslate("Settings", 'Show X graduation'), qsTranslate("Settings", "Show X graduation"),
"default_graph.showxgrad", "default_graph.showxgrad",
"showxgrad" "showxgrad"
) )
const SHOW_Y_GRAD = new BoolSetting( const SHOW_Y_GRAD = new BoolSetting(
qsTranslate("Settings", 'Show Y graduation'), qsTranslate("Settings", "Show Y graduation"),
"default_graph.showygrad", "default_graph.showygrad",
"showygrad" "showygrad"
) )

View file

@ -16,30 +16,30 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import {BoolSetting, EnumIntSetting} from "./common.mjs" import { BoolSetting, EnumIntSetting } from "./common.mjs"
const AUTOCLOSE_FORMULA = new BoolSetting( const AUTOCLOSE_FORMULA = new BoolSetting(
qsTranslate("expression", "Automatically close parenthesises and brackets"), qsTranslate("expression", "Automatically close parenthesises and brackets"),
'expression_editor.autoclose', "expression_editor.autoclose",
'text' "text"
) )
const ENABLE_SYNTAX_HIGHLIGHTING = new BoolSetting( const ENABLE_SYNTAX_HIGHLIGHTING = new BoolSetting(
qsTranslate("expression", "Enable syntax highlighting"), qsTranslate("expression", "Enable syntax highlighting"),
'expression_editor.colorize', "expression_editor.colorize",
'appearance' "appearance"
) )
const ENABLE_AUTOCOMPLETE = new BoolSetting( const ENABLE_AUTOCOMPLETE = new BoolSetting(
qsTranslate("expression", "Enable autocompletion"), qsTranslate("expression", "Enable autocompletion"),
'autocompletion.enabled', "autocompletion.enabled",
'label' "label"
) )
const PICK_COLOR_SCHEME = new EnumIntSetting( const PICK_COLOR_SCHEME = new EnumIntSetting(
qsTranslate("expression", "Color Scheme"), qsTranslate("expression", "Color Scheme"),
'expression_editor.color_scheme', "expression_editor.color_scheme",
'color', "color",
["Breeze Light", "Breeze Dark", "Solarized", "Github Light", "Github Dark", "Nord", "Monokai"] ["Breeze Light", "Breeze Dark", "Solarized", "Github Light", "Github Dark", "Nord", "Monokai"]
) )

View file

@ -16,25 +16,25 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import {BoolSetting} from "./common.mjs" import { BoolSetting } from "./common.mjs"
import Canvas from "../module/canvas.mjs" import Canvas from "../module/canvas.mjs"
import LatexAPI from "../module/latex.mjs" import LatexAPI from "../module/latex.mjs"
const CHECK_FOR_UPDATES = new BoolSetting( const CHECK_FOR_UPDATES = new BoolSetting(
qsTranslate("general", "Check for updates on startup"), qsTranslate("general", "Check for updates on startup"),
'check_for_updates', "check_for_updates",
'update' "update"
) )
const RESET_REDO_STACK = new BoolSetting( const RESET_REDO_STACK = new BoolSetting(
qsTranslate("general", "Reset redo stack automaticly"), qsTranslate("general", "Reset redo stack automaticly"),
'reset_redo_stack', "reset_redo_stack",
'timeline' "timeline"
) )
class EnableLatex extends BoolSetting { class EnableLatex extends BoolSetting {
constructor() { constructor() {
super(qsTranslate("general","Enable LaTeX rendering"), 'enable_latex', 'Expression') super(qsTranslate("general", "Enable LaTeX rendering"), "enable_latex", "Expression")
} }
set(value) { set(value) {

View file

@ -16,6 +16,25 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
// Add string methods
/**
* Replaces latin characters with their uppercase versions.
* @return {string}
*/
String.prototype.toLatinUppercase = String.prototype.toLatinUppercase || function() {
return this.replace(/[a-z]/g, function(match) {
return match.toUpperCase()
})
}
/**
* Removes the 'enclosers' of a string (e.g. quotes, parentheses, brackets...)
* @return {string}
*/
String.prototype.removeEnclosure = function() {
return this.substring(1, this.length - 1)
}
const powerpos = { const powerpos = {
"-": "⁻", "-": "⁻",
"+": "⁺", "+": "⁺",
@ -350,10 +369,6 @@ export function parseName(str, removeUnallowed = true) {
return str return str
} }
String.prototype.toLatinUppercase = function() {
return this.replace(/[a-z]/g, function(match){return match.toUpperCase()})
}
/** /**
* Transforms camel case strings to a space separated one. * Transforms camel case strings to a space separated one.
* *

View file

@ -29,7 +29,7 @@ class LOG_COLORS:
GRAY = "\033[90m" GRAY = "\033[90m"
BLUE = "\033[94m" BLUE = "\033[94m"
ORANGE = "\033[38;5;166m" ORANGE = "\033[38;5;166m"
RED = "\033[e[38;5;204m" RED = "\033[38;5;204m"
INVERT = "\033[7m" INVERT = "\033[7m"
RESET_INVERT = "\033[27m" RESET_INVERT = "\033[27m"
RESET = "\033[0m" RESET = "\033[0m"

138
package-lock.json generated
View file

@ -13,7 +13,6 @@
"@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-commonjs": "^28.0.0", "@rollup/plugin-commonjs": "^28.0.0",
"@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-terser": "^0.4.4",
"install": "^0.13.0", "install": "^0.13.0",
"rollup": "^4.22.4", "rollup": "^4.22.4",
"rollup-plugin-cleanup": "^3.2.1" "rollup-plugin-cleanup": "^3.2.1"
@ -1724,16 +1723,6 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@jridgewell/source-map": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
}
},
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
@ -1838,28 +1827,6 @@
} }
} }
}, },
"node_modules/@rollup/plugin-terser": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
"license": "MIT",
"dependencies": {
"serialize-javascript": "^6.0.1",
"smob": "^1.0.0",
"terser": "^5.17.4"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/pluginutils": { "node_modules/@rollup/pluginutils": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz",
@ -2114,18 +2081,6 @@
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/acorn": {
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ansi-styles": { "node_modules/ansi-styles": {
"version": "3.2.1", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
@ -2209,12 +2164,6 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
} }
}, },
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"license": "MIT"
},
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001663", "version": "1.0.30001663",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz",
@ -2264,12 +2213,6 @@
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"license": "MIT"
},
"node_modules/commondir": { "node_modules/commondir": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@ -2602,15 +2545,6 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"license": "MIT",
"dependencies": {
"safe-buffer": "^5.1.0"
}
},
"node_modules/regenerate": { "node_modules/regenerate": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@ -2770,26 +2704,6 @@
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/semver": { "node_modules/semver": {
"version": "6.3.1", "version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@ -2799,15 +2713,6 @@
"semver": "bin/semver.js" "semver": "bin/semver.js"
} }
}, },
"node_modules/serialize-javascript": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"license": "BSD-3-Clause",
"dependencies": {
"randombytes": "^2.1.0"
}
},
"node_modules/skip-regex": { "node_modules/skip-regex": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/skip-regex/-/skip-regex-1.0.2.tgz", "resolved": "https://registry.npmjs.org/skip-regex/-/skip-regex-1.0.2.tgz",
@ -2817,31 +2722,6 @@
"node": ">=4.2" "node": ">=4.2"
} }
}, },
"node_modules/smob": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz",
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
"license": "MIT"
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/source-map-support/node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/sourcemap-codec": { "node_modules/sourcemap-codec": {
"version": "1.4.8", "version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
@ -2873,24 +2753,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/terser": {
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.33.0.tgz",
"integrity": "sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g==",
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"engines": {
"node": ">=10"
}
},
"node_modules/to-fast-properties": { "node_modules/to-fast-properties": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",

View file

@ -17,7 +17,6 @@
"@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-commonjs": "^28.0.0", "@rollup/plugin-commonjs": "^28.0.0",
"@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-terser": "^0.4.4",
"install": "^0.13.0", "install": "^0.13.0",
"rollup": "^4.22.4", "rollup": "^4.22.4",
"rollup-plugin-cleanup": "^3.2.1" "rollup-plugin-cleanup": "^3.2.1"

View file

@ -20,7 +20,6 @@ import { nodeResolve } from "@rollup/plugin-node-resolve"
import commonjs from "@rollup/plugin-commonjs" import commonjs from "@rollup/plugin-commonjs"
import { babel } from "@rollup/plugin-babel" import { babel } from "@rollup/plugin-babel"
import cleanup from "rollup-plugin-cleanup" import cleanup from "rollup-plugin-cleanup"
import terser from "@rollup/plugin-terser"
const path = "LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js" const path = "LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js"
@ -39,9 +38,6 @@ export default {
babel({ babel({
babelHelpers: "bundled" babelHelpers: "bundled"
}), }),
// terser({
// ecma: 2015
// })
] ]
} }