Switching a lot of stuff to new Settings module

+ Fixing a bug that did not load the showygrad setting properly.
This commit is contained in:
Adsooi 2024-10-10 19:15:46 +02:00
parent f4920aadb6
commit d1ac70a946
Signed by: Ad5001
GPG key ID: EF45F9C6AFE20160
11 changed files with 148 additions and 229 deletions

View file

@ -38,7 +38,7 @@ export class BaseEvent {
export class BaseEventEmitter {
static emits = []
/** @type {Record<string, function[]>} */
/** @type {Record<string, Set<function>>} */
#listeners = {}
constructor() {
@ -54,7 +54,7 @@ export class BaseEventEmitter {
* @param {function(BaseEvent)} eventListener - The function to be called back when the event is emitted.
*/
addEventListener(eventType, eventListener) {
if(!this.emits.includes(eventType)) {
if(!this.constructor.emits.includes(eventType)) {
const className = this.constructor.name
const eventTypes = this.constructor.emits.join(", ")
throw new Error(`Cannot listen to unknown event ${eventType} in class ${className}. ${className} only emits: ${eventTypes}`)
@ -71,7 +71,7 @@ export class BaseEventEmitter {
* @returns {boolean} True if the listener was removed, false if it was not found.
*/
removeEventListener(eventType, eventListener) {
if(!this.emits.includes(eventType)) {
if(!this.constructor.emits.includes(eventType)) {
const className = this.constructor.name
const eventTypes = this.constructor.emits.join(", ")
throw new Error(`Cannot listen to unknown event ${eventType} in class ${className}. ${className} only emits: ${eventTypes}`)
@ -88,8 +88,11 @@ export class BaseEventEmitter {
emit(e) {
if(!(e instanceof BaseEvent))
throw new Error("Cannot emit non event object.")
if(!this.emits.includes(e.name))
throw new Error(`Cannot emit event '${e.name}' from class ${this.constructor.name}. ${this.constructor.name} can only emits: ${this.constructor.emits.join(", ")}.`)
if(!this.constructor.emits.includes(e.name)) {
const className = this.constructor.name
const eventTypes = this.constructor.emits.join(", ")
throw new Error(`Cannot emit event '${e.name}' from class ${className}. ${className} can only emit: ${eventTypes}`)
}
for(const listener of this.#listeners[e.name])
listener(e)
}

View file

@ -23,6 +23,7 @@ import { Expression } from "../math/index.mjs"
import Latex from "./latex.mjs"
import Objects from "./objects.mjs"
import History from "./history.mjs"
import Settings from "./settings.mjs"
class CanvasAPI extends Module {
/** @type {CanvasInterface} */
@ -84,7 +85,7 @@ class CanvasAPI extends Module {
*/
get xmin() {
if(!this.initialized) throw new Error("Attempting xmin before initialize!")
return this.#canvas.xmin
return Settings.xmin
}
/**
@ -93,7 +94,7 @@ class CanvasAPI extends Module {
*/
get xzoom() {
if(!this.initialized) throw new Error("Attempting xzoom before initialize!")
return this.#canvas.xzoom
return Settings.xzoom
}
/**
@ -102,7 +103,7 @@ class CanvasAPI extends Module {
*/
get ymax() {
if(!this.initialized) throw new Error("Attempting ymax before initialize!")
return this.#canvas.ymax
return Settings.ymax
}
/**
@ -111,7 +112,7 @@ class CanvasAPI extends Module {
*/
get yzoom() {
if(!this.initialized) throw new Error("Attempting yzoom before initialize!")
return this.#canvas.yzoom
return Settings.yzoom
}
/**
@ -120,7 +121,7 @@ class CanvasAPI extends Module {
*/
get xlabel() {
if(!this.initialized) throw new Error("Attempting xlabel before initialize!")
return this.#canvas.xlabel
return Settings.xlabel
}
/**
@ -129,7 +130,7 @@ class CanvasAPI extends Module {
*/
get ylabel() {
if(!this.initialized) throw new Error("Attempting ylabel before initialize!")
return this.#canvas.ylabel
return Settings.ylabel
}
/**
@ -138,7 +139,7 @@ class CanvasAPI extends Module {
*/
get linewidth() {
if(!this.initialized) throw new Error("Attempting linewidth before initialize!")
return this.#canvas.linewidth
return Settings.linewidth
}
/**
@ -147,7 +148,7 @@ class CanvasAPI extends Module {
*/
get textsize() {
if(!this.initialized) throw new Error("Attempting textsize before initialize!")
return this.#canvas.textsize
return Settings.textsize
}
/**
@ -156,7 +157,7 @@ class CanvasAPI extends Module {
*/
get logscalex() {
if(!this.initialized) throw new Error("Attempting logscalex before initialize!")
return this.#canvas.logscalex
return Settings.logscalex
}
/**
@ -165,7 +166,7 @@ class CanvasAPI extends Module {
*/
get showxgrad() {
if(!this.initialized) throw new Error("Attempting showxgrad before initialize!")
return this.#canvas.showxgrad
return Settings.showxgrad
}
/**
@ -174,7 +175,7 @@ class CanvasAPI extends Module {
*/
get showygrad() {
if(!this.initialized) throw new Error("Attempting showygrad before initialize!")
return this.#canvas.showygrad
return Settings.showygrad
}
/**
@ -237,9 +238,9 @@ class CanvasAPI extends Module {
* @private
*/
_computeAxes() {
let exprY = new Expression(`x*(${this.#canvas.yaxisstep})`)
let exprY = new Expression(`x*(${Settings.yaxisstep})`)
let y1 = exprY.execute(1)
let exprX = new Expression(`x*(${this.#canvas.xaxisstep})`)
let exprX = new Expression(`x*(${Settings.xaxisstep})`)
let x1 = exprX.execute(1)
this.axesSteps = {
x: {

View file

@ -17,6 +17,7 @@
*/
import Objects from "./objects.mjs"
import Settings from "./settings.mjs"
import ExprParser from "./expreval.mjs"
import Latex from "./latex.mjs"
import History from "./history.mjs"
@ -26,6 +27,7 @@ import Preferences from "./preferences.mjs"
export default {
Objects,
Settings,
ExprParser,
Latex,
History,

View file

@ -78,7 +78,7 @@ export class SettingsInterface extends Interface {
showygrad = BOOLEAN
}
export class CanvasInterface extends SettingsInterface {
export class CanvasInterface extends Interface {
imageLoaders = OBJECT
/** @type {function(string): CanvasRenderingContext2D} */
getContext = FUNCTION

View file

@ -20,22 +20,20 @@ import { Module } from "./common.mjs"
import Objects from "./objects.mjs"
import History from "./history.mjs"
import Canvas from "./canvas.mjs"
import Settings from "./settings.mjs"
import { DialogInterface, RootInterface, SettingsInterface } from "./interface.mjs"
class IOAPI extends Module {
/** @type {RootInterface} */
#rootElement
/** @type {SettingsInterface} */
#settings
/** @type {{show: function(string)}} */
#alert
constructor() {
super("IO", {
alert: DialogInterface,
root: RootInterface,
settings: SettingsInterface
root: RootInterface
})
/**
* Path of the currently opened file. Empty if no file is opened.
@ -47,13 +45,11 @@ class IOAPI extends Module {
/**
* Initializes module with QML elements.
* @param {RootInterface} root
* @param {SettingsInterface} settings
* @param {{show: function(string)}} alert
*/
initialize({ root, settings, alert }) {
super.initialize({ root, settings, alert })
initialize({ root, alert }) {
super.initialize({ root, alert })
this.#rootElement = root
this.#settings = settings
this.#alert = alert
}
@ -75,19 +71,19 @@ class IOAPI extends Module {
}
}
let settings = {
"xzoom": this.#settings.xzoom,
"yzoom": this.#settings.yzoom,
"xmin": this.#settings.xmin,
"ymax": this.#settings.ymax,
"xaxisstep": this.#settings.xaxisstep,
"yaxisstep": this.#settings.yaxisstep,
"xaxislabel": this.#settings.xlabel,
"yaxislabel": this.#settings.ylabel,
"logscalex": this.#settings.logscalex,
"linewidth": this.#settings.linewidth,
"showxgrad": this.#settings.showxgrad,
"showygrad": this.#settings.showygrad,
"textsize": this.#settings.textsize,
"xzoom": Settings.xzoom,
"yzoom": Settings.yzoom,
"xmin": Settings.xmin,
"ymax": Settings.ymax,
"xaxisstep": Settings.xaxisstep,
"yaxisstep": Settings.yaxisstep,
"xaxislabel": Settings.xlabel,
"yaxislabel": Settings.ylabel,
"logscalex": Settings.logscalex,
"linewidth": Settings.linewidth,
"showxgrad": Settings.showxgrad,
"showygrad": Settings.showygrad,
"textsize": Settings.textsize,
"history": History.serialize(),
"width": this.#rootElement.width,
"height": this.#rootElement.height,
@ -113,24 +109,24 @@ class IOAPI extends Module {
if(data.hasOwnProperty("type") && data["type"] === "logplotv1") {
History.clear()
// Importing settings
this.#settings.saveFilename = filename
this.#settings.xzoom = parseFloat(data["xzoom"]) || 100
this.#settings.yzoom = parseFloat(data["yzoom"]) || 10
this.#settings.xmin = parseFloat(data["xmin"]) || 5 / 10
this.#settings.ymax = parseFloat(data["ymax"]) || 24
this.#settings.xaxisstep = data["xaxisstep"] || "4"
this.#settings.yaxisstep = data["yaxisstep"] || "4"
this.#settings.xlabel = data["xaxislabel"] || ""
this.#settings.ylabel = data["yaxislabel"] || ""
this.#settings.logscalex = data["logscalex"] === true
Settings.set("saveFilename", filename, false)
Settings.set("xzoom", parseFloat(data["xzoom"]) || 100, false)
Settings.set("yzoom", parseFloat(data["yzoom"]) || 10, false)
Settings.set("xmin", parseFloat(data["xmin"]) || 5 / 10, false)
Settings.set("ymax", parseFloat(data["ymax"]) || 24, false)
Settings.set("xaxisstep", data["xaxisstep"] || "4", false)
Settings.set("yaxisstep", data["yaxisstep"] || "4", false)
Settings.set("xlabel", data["xaxislabel"] || "", false)
Settings.set("ylabel", data["yaxislabel"] || "", false)
Settings.set("logscalex", data["logscalex"] === true, false)
if("showxgrad" in data)
this.#settings.showxgrad = data["showxgrad"]
Settings.set("showxgrad", data["showxgrad"], false)
if("showygrad" in data)
this.#settings.textsize = data["showygrad"]
Settings.set("showygrad", data["showygrad"], false)
if("linewidth" in data)
this.#settings.linewidth = data["linewidth"]
Settings.set("linewidth", data["linewidth"], false)
if("textsize" in data)
this.#settings.textsize = data["textsize"]
Settings.set("textsize", data["textsize"], false)
this.#rootElement.height = parseFloat(data["height"]) || 500
this.#rootElement.width = parseFloat(data["width"]) || 1000

View file

@ -18,6 +18,7 @@
import { Module } from "./common.mjs"
import { BaseEvent } from "../events.mjs"
import { HelperInterface } from "./interface.mjs"
/**
@ -48,19 +49,20 @@ class SettingsAPI extends Module {
static emits = ["changed"]
#properties = new Map([
['xzoom', 100],
['yzoom', 10],
['xmin', .5],
['ymax', 25],
['xaxisstep', "4"],
['yaxisstep', "4"],
['xlabel', ""],
['ylabel', ""],
['linewidth', 1],
['textsize', 18],
['logscalex', true],
['showxgrad', true],
['showygrad', true],
["saveFilename", ""],
["xzoom", 100],
["yzoom", 10],
["xmin", .5],
["ymax", 25],
["xaxisstep", "4"],
["yaxisstep", "4"],
["xlabel", ""],
["ylabel", ""],
["linewidth", 1],
["textsize", 18],
["logscalex", true],
["showxgrad", true],
["showygrad", true]
])
constructor() {
@ -74,14 +76,14 @@ class SettingsAPI extends Module {
// Initialize default values.
for(const key of this.#properties.keys()) {
switch(typeof this.#properties.get(key)) {
case 'boolean':
this.set(key, helper.getSettingBool(key), false)
case "boolean":
this.set(key, helper.getSettingBool("default_graph."+key), false)
break
case 'number':
this.set(key, helper.getSettingInt(key), false)
case "number":
this.set(key, helper.getSettingInt("default_graph."+key), false)
break
case 'string':
this.set(key, helper.getSetting(key), false)
case "string":
this.set(key, helper.getSetting("default_graph."+key), false)
break
}
}
@ -89,16 +91,20 @@ class SettingsAPI extends Module {
/**
* Sets a setting to a given value
*
* @param {boolean} byUser - Set to true if the user is at the origin of this change.
*
* @param {string} property
* @param {string|number|boolean} value
* @param {boolean} byUser - Set to true if the user is at the origin of this change.
*/
set(property, value, byUser) {
if(!this.#properties.has(property))
if(!this.#properties.has(property)) {
throw new Error(`Property ${property} is not a setting.`)
}
const oldValue = this.#properties.get(property)
console.debug("Setting", property, "from", oldValue, "to", value, `(${typeof value}, ${byUser})`)
const propType = typeof oldValue
if(propType !== typeof value)
throw new Error(`Value of ${property} must be a ${propType}.`)
throw new Error(`Value of ${property} must be a ${propType} (${typeof value} provided).`)
this.#properties.set(property, value)
this.emit(new ChangedEvent(property, oldValue, value, byUser === true))
}
@ -107,67 +113,70 @@ class SettingsAPI extends Module {
* Zoom on the x axis of the diagram.
* @returns {number}
*/
get xzoom() { return this.#properties.get("xzoom"); }
get xzoom() { return this.#properties.get("xzoom") }
/**
* Zoom on the y axis of the diagram.
* @returns {number}
*/
get yzoom() { return this.#properties.get("yzoom"); }
get yzoom() { return this.#properties.get("yzoom") }
/**
* Minimum x of the diagram.
* @returns {number}
*/
get xmin() { return this.#properties.get("xmin"); }
get xmin() { return this.#properties.get("xmin") }
/**
* Maximum y of the diagram.
* @returns {number}
*/
get ymax() { return this.#properties.get("ymax"); }
get ymax() { return this.#properties.get("ymax") }
/**
* Step of the x axis graduation (expression).
* @note Only available in non-logarithmic mode.
* @returns {string}
*/
get xaxisstep() { return this.#properties.get("xaxisstep"); }
get xaxisstep() { return this.#properties.get("xaxisstep") }
/**
* Step of the y axis graduation (expression).
* @returns {string}
*/
get yaxisstep() { return this.#properties.get("yaxisstep"); }
get yaxisstep() { return this.#properties.get("yaxisstep") }
/**
* Label used on the x axis.
* @returns {string}
*/
get xlabel() { return this.#properties.get("xlabel"); }
get xlabel() { return this.#properties.get("xlabel") }
/**
* Label used on the y axis.
* @returns {string}
*/
get ylabel() { return this.#properties.get("ylabel"); }
get ylabel() { return this.#properties.get("ylabel") }
/**
* Width of lines that will be drawn into the canvas.
* @returns {number}
*/
get linewidth() { return this.#properties.get("linewidth"); }
get linewidth() { return this.#properties.get("linewidth") }
/**
* Font size of the text that will be drawn into the canvas.
* @returns {number}
*/
get textsize() { return this.#properties.get("textsize"); }
get textsize() { return this.#properties.get("textsize") }
/**
* true if the canvas should be in logarithmic mode, false otherwise.
* @returns {boolean}
*/
get logscalex() { return this.#properties.get("logscalex"); }
get logscalex() { return this.#properties.get("logscalex") }
/**
* true if the x graduation should be shown, false otherwise.
* @returns {boolean}
*/
get showxgrad() { return this.#properties.get("showxgrad"); }
get showxgrad() { return this.#properties.get("showxgrad") }
/**
* true if the y graduation should be shown, false otherwise.
* @returns {boolean}
*/
get showygrad() { return this.#properties.get("showygrad"); }
get showygrad() { return this.#properties.get("showygrad") }
}
Modules.Settings = Modules.Settings || new SettingsAPI()
export default Modules.Settings

View file

@ -35,6 +35,19 @@ String.prototype.removeEnclosure = function() {
return this.substring(1, this.length - 1)
}
/**
* Rounds to a certain number of decimal places.
* From https://stackoverflow.com/a/48764436
*
* @param {number} decimalPlaces
* @return {number}
*/
Number.prototype.toDecimalPrecision = function(decimalPlaces = 0) {
const p = Math.pow(10, decimalPlaces);
const n = (this * p) * (1 + Number.EPSILON);
return Math.round(n) / p;
}
const powerpos = {
"-": "⁻",
"+": "⁺",