Skip to content

Commit 9da3cef

Browse files
committed
- Add decimal separator option
- Add tip renderer option - Add Derivatives - Add editing screen. (partially)
1 parent 05a6ce7 commit 9da3cef

11 files changed

Lines changed: 169 additions & 46 deletions

File tree

src/app/CreatePlotModal.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,27 @@ import { insertPlot } from "../common/utils";
88
export default class CreatePlotModal extends Modal {
99
plugin: ObsidianFunctionPlot;
1010
editor: Editor;
11+
options: PlotInputs;
12+
onSubmit: (options: PlotInputs, renderer: rendererType) => void;
1113

12-
constructor(plugin: ObsidianFunctionPlot, editor: Editor) {
14+
constructor(
15+
plugin: ObsidianFunctionPlot,
16+
editor: Editor,
17+
options?: PlotInputs,
18+
onSubmit?: () => void
19+
) {
1320
super(plugin.app);
1421
this.plugin = plugin;
1522
this.editor = editor;
23+
this.options =
24+
options ??
25+
(JSON.parse(JSON.stringify(DEFAULT_PLOT_INPUTS)) as PlotInputs);
26+
this.onSubmit =
27+
onSubmit ??
28+
((options: PlotInputs, renderer: rendererType) => {
29+
insertPlot(this.plugin, this.editor, options, renderer);
30+
this.close();
31+
});
1632
}
1733

1834
onOpen() {
@@ -23,12 +39,9 @@ export default class CreatePlotModal extends Modal {
2339
new PlotModal({
2440
target: this.contentEl,
2541
props: {
26-
options: JSON.parse(JSON.stringify(DEFAULT_PLOT_INPUTS)) as PlotInputs,
42+
options: this.options,
2743
plugin: this.plugin,
28-
submit: (options: PlotInputs, renderer: rendererType) => {
29-
insertPlot(this.plugin, this.editor, options, renderer);
30-
this.close();
31-
},
44+
submit: this.onSubmit,
3245
},
3346
});
3447
}

src/app/SettingsTab.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ export default class SettingsTab extends PluginSettingTab {
4444
});
4545
});
4646

47+
new Setting(containerEl)
48+
.setName("Decimal Separator")
49+
.setDesc("The character used as the decimal separator.")
50+
.addText((text) => {
51+
this.settingsInputs.set("decimalSeparator", text);
52+
text
53+
.setValue(this.plugin.settings.decimalSeparator)
54+
.onChange(async (value) => {
55+
this.plugin.settings.decimalSeparator = value;
56+
await this.plugin.saveSettings();
57+
});
58+
});
59+
4760
/*
4861
* Font Sizes
4962
*/

src/common/defaults.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import type {
1111
* The default plugin settings.
1212
*/
1313
export const DEFAULT_PLUGIN_SETTINGS: Required<PluginSettings> = {
14+
decimalSeparator: ".",
15+
1416
titleFontSize: 24,
1517
scaleFontSize: 12,
1618
labelFontSize: 12,
@@ -59,6 +61,10 @@ export const DEFAULT_FUNCTION_INPUTS: Omit<FunctionInputs, "fn" | "r"> = {
5961
graphType: "polyline",
6062
nSamples: undefined,
6163
points: DEFAULT_POINTS,
64+
derivative: {
65+
fn: "",
66+
updateOnMouseMove: true,
67+
},
6268
};
6369

6470
export const FALLBACK_FUNCTION_INPUTS: DeepNonNullable<
@@ -88,23 +94,15 @@ export const DEFAULT_PLOT_INPUTS: PlotInputs = {
8894
constants: {},
8995
legends: false,
9096
xAxis: {
91-
label: undefined,
92-
domain: {
93-
min: undefined,
94-
max: undefined,
95-
},
97+
domain: {},
9698
},
9799
yAxis: {
98-
label: undefined,
99-
domain: {
100-
min: undefined,
101-
max: undefined,
102-
},
100+
domain: {},
103101
},
104102
grid: true,
105103
data: [],
106-
disableZoom: undefined,
107104
title: undefined,
105+
tip: {},
108106
};
109107

110108
export const FALLBACK_PLOT_INPUTS: DeepNonNullable<

src/common/types.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ export type DeepNonNullable<T> = {
2020
[K in keyof T]: DeepNonNullable<Required<T[K]>>;
2121
};
2222

23+
export interface DerivativeInputs {
24+
fn: string;
25+
x0?: number;
26+
updateOnMouseMove: boolean;
27+
}
28+
2329
export interface FunctionInputs {
2430
id?: string;
2531
name?: string;
@@ -45,13 +51,22 @@ export interface FunctionInputs {
4551
nSamples?: number;
4652
closed?: boolean;
4753
skipTip?: boolean;
54+
derivative: DerivativeInputs;
4855
}
56+
4957
export interface ConstantInputs {
5058
min: number;
5159
max: number;
5260
step: number;
5361
value: number;
5462
}
63+
64+
export interface TipInputs {
65+
renderer?: string;
66+
xLine?: boolean;
67+
yLine?: boolean;
68+
}
69+
5570
/**
5671
* An interface specifying the options for a plot.
5772
*/
@@ -76,6 +91,7 @@ export interface PlotInputs {
7691
grid?: boolean;
7792
disableZoom?: boolean;
7893
title?: string;
94+
tip: TipInputs;
7995
}
8096

8197
export interface V1YAMLPlotInputs {
@@ -91,6 +107,8 @@ export interface V1YAMLPlotInputs {
91107
* The plugin's settings.
92108
*/
93109
export interface PluginSettings {
110+
decimalSeparator: string;
111+
94112
titleFontSize: number;
95113
scaleFontSize: number;
96114
labelFontSize: number;

src/common/utils.ts

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,22 @@ import { toPng } from "html-to-image";
1717
import type {
1818
FunctionPlotDatum,
1919
FunctionPlotOptions,
20+
FunctionPlotTip,
2021
} from "function-plot/dist/types";
2122
import { FunctionPlot } from "../fnplot";
2223

2324
export function gcd(a: number, b: number): number {
2425
return !b ? a : gcd(b, a % b);
2526
}
2627

27-
function parseLaTeX(latex: string | undefined): string | undefined {
28+
function parseLaTeX(
29+
latex: string | undefined,
30+
plugin: ObsidianFunctionPlot
31+
): string | undefined {
2832
return latex === undefined
2933
? latex
3034
: latex
35+
.replace(plugin.settings.decimalSeparator, ".")
3136
.replace("f(x)=", "")
3237
.replace(/\\frac\{([^{}]+)\}\{([^{}]+)\}/g, "($1)/($2)")
3338
.replace(/\\cdot/g, "*")
@@ -49,17 +54,19 @@ function parseLaTeX(latex: string | undefined): string | undefined {
4954
// TODO make change to returned object reflect in input
5055
export function toFunctionPlotOptions(
5156
options: PlotInputs,
52-
target: HTMLElement
57+
target: HTMLElement,
58+
plugin: ObsidianFunctionPlot
5359
): FunctionPlotOptions {
5460
function functionInputsToFunctionPlotDatum(
55-
inputs: FunctionInputs
61+
inputs: FunctionInputs,
62+
plugin: ObsidianFunctionPlot
5663
): FunctionPlotDatum {
5764
const output: FunctionPlotDatum = {
5865
fnType: inputs.fnType,
5966
graphType: inputs.graphType ?? undefined,
6067
fn:
6168
inputs.fnType === "linear"
62-
? parseLaTeX(inputs.fn) ?? undefined
69+
? parseLaTeX(inputs.fn, plugin) ?? undefined
6370
: undefined,
6471
points:
6572
inputs.fnType === "points" && inputs.points !== DEFAULT_POINTS
@@ -98,6 +105,14 @@ export function toFunctionPlotOptions(
98105
nSamples: inputs.nSamples ? Math.min(inputs.nSamples, 999) : undefined,
99106
closed: inputs.closed ?? undefined,
100107
skipTip: inputs.skipTip ?? undefined,
108+
derivative:
109+
inputs.derivative?.fn === ""
110+
? undefined
111+
: {
112+
fn: parseLaTeX(inputs.derivative?.fn, plugin),
113+
x0: inputs.derivative?.x0 ?? undefined,
114+
updateOnMouseMove: inputs.derivative?.updateOnMouseMove ?? true,
115+
},
101116
};
102117

103118
Object.keys(output).forEach(
@@ -123,7 +138,7 @@ export function toFunctionPlotOptions(
123138
target: target,
124139
data: options.data
125140
.filter(hasFunction)
126-
.map(functionInputsToFunctionPlotDatum),
141+
.map((data) => functionInputsToFunctionPlotDatum(data, plugin)),
127142
title: options.title ?? undefined,
128143
xAxis: {
129144
label: options.xAxis.label ?? FALLBACK_PLOT_INPUTS.xAxis.label,
@@ -141,6 +156,17 @@ export function toFunctionPlotOptions(
141156
},
142157
grid: options.grid ?? undefined,
143158
disableZoom: options.disableZoom ?? undefined,
159+
tip: {
160+
renderer: (x: number, y: number, index: number) => {
161+
return options.tip.renderer === undefined || options.tip.renderer === ""
162+
? "(" + x.toFixed(2).toString() + "," + y.toFixed(2).toString() + ")"
163+
: options.tip.renderer
164+
.replace("x", x.toFixed(2).toString())
165+
.replace("y", y.toFixed(2).toString());
166+
},
167+
xLine: options.tip.xLine ?? undefined,
168+
yLine: options.tip.yLine ?? undefined,
169+
} as FunctionPlotTip,
144170
};
145171

146172
Object.keys(output).forEach(
@@ -291,6 +317,7 @@ export function parseYAMLCodeBlock(content: string): PlotInputs {
291317
fn, // return as FunctionInputs since fn is specified here
292318
}) as FunctionInputs;
293319
}),
320+
tip: {},
294321
};
295322
}
296323

src/components/Plot/Plot.svelte

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
import type { PlotInputs } from "../../common/types";
33
import type ObsidianFunctionPlot from "../../main";
44
import Constant from "./Constant.svelte";
5-
import { Menu } from "obsidian";
5+
import { MarkdownView, Menu } from "obsidian";
66
77
import { FunctionPlot } from "../../fnplot";
88
import { onMount } from "svelte";
9+
import PlotModal from "../PlotModal/PlotModal.svelte";
10+
import CreatePlotModal from "../../app/CreatePlotModal";
11+
import { timeHours } from "d3";
12+
import { insertPlot } from "../../common/utils";
913
1014
export let options: PlotInputs,
1115
plugin: ObsidianFunctionPlot,
@@ -81,7 +85,22 @@
8185
item.setTitle("Edit");
8286
item.setIcon("pencil");
8387
item.onClick(() => {
84-
console.log("to be implemented");
88+
const activeLeaf =
89+
plugin.app.workspace.getActiveViewOfType(MarkdownView);
90+
91+
if (!activeLeaf) {
92+
return;
93+
}
94+
95+
new CreatePlotModal(
96+
plugin,
97+
activeLeaf.editor,
98+
options,
99+
(options: PlotInputs, renderer: rendererType) => {
100+
insertPlot(this.plugin, this.editor, options, renderer);
101+
this.close();
102+
}
103+
).open();
85104
});
86105
});
87106
}
@@ -90,7 +109,7 @@
90109
}
91110
</script>
92111

93-
<div on:contextmenu={handleContextMenu}>
112+
<div on:contextmenu={handleContextMenu} role="application">
94113
<div class="fplt-plot" bind:this={plotContainer} />
95114
<div class="fplt-plot-options">
96115
<div class="fplt-constants">

src/components/PlotModal/Function.svelte

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@
1414
1515
export let datum: FunctionInputs, unmount: () => void, legends: boolean;
1616
17-
let showFloater = false;
18-
let mousePos = { x: 0, y: 0 };
19-
2017
let points = 1;
2118
19+
let mousePos = { x: 0, y: 0 };
20+
let showFloater = false;
2221
function handleClick(e: MouseEvent) {
2322
showFloater = true;
2423
const target = (e.target as HTMLElement).closest("div");
@@ -110,7 +109,7 @@
110109
<option value="scatter">scatter</option>
111110
{#if !["polar", "vector", "points"].includes(datum.fnType)}
112111
<option value="interval">interval</option>
113-
{/if} -->
112+
{/if}
114113
</Dropdown>
115114
{/if}
116115
{#if datum.fnType !== "vector"}
@@ -138,6 +137,10 @@
138137
<label for="skip-tip">Skip tip</label>
139138
<Switch id="skip-tip" bind:checked={datum.skipTip} />
140139
{/if}
140+
{#if datum.fnType == "linear"}
141+
<label for="derivative">Derivative</label>
142+
<TextInput id="derivative" bind:value={datum.derivative.fn} />
143+
{/if}
141144
</OptionsFloater>
142145
{/if}
143146
</div>

0 commit comments

Comments
 (0)