11import type { FunctionPlotDatum } from "function-plot/dist/types" ;
22import { Editor , Modal , Setting } from "obsidian" ;
3- import { DEFAULT_PLOT_OPTIONS } from "../common/defaults" ;
3+ import {
4+ DEFAULT_FUNCTION_OPTIONS ,
5+ DEFAULT_PLOT_OPTIONS ,
6+ FUNCTION_CASES ,
7+ } from "../common/defaults" ;
48import type { PlotOptions , rendererType , Line } from "../common/types" ;
59import type ObsidianFunctionPlot from "../main" ;
610import { createPlot , renderPlotAsInteractive } from "../common/utils" ;
@@ -36,12 +40,14 @@ export default class CreatePlotModal extends Modal {
3640 this . plot . options . data = this . options . functions . map (
3741 ( line ) : FunctionPlotDatum => {
3842 // use polyline by default
39- const lineProperties : Line = { graphType : "polyline" } ;
43+ const lineProperties : Line = { graphType : "polyline" } ;
4044
4145 line . split ( "@" ) . forEach ( ( property ) => {
4246 const tup = property . split ( "=" ) ;
43- const value = tup [ 1 ] . trim ( )
44- lineProperties [ tup [ 0 ] . trim ( ) ] = value . startsWith ( "[" ) ? JSON . parse ( value ) : value ;
47+ const value = tup [ 1 ] . trim ( ) ;
48+ lineProperties [ tup [ 0 ] . trim ( ) ] = value . startsWith ( "[" )
49+ ? JSON . parse ( value )
50+ : value ;
4551 } ) ;
4652
4753 return lineProperties ;
@@ -55,8 +61,16 @@ export default class CreatePlotModal extends Modal {
5561 }
5662 }
5763
64+ computeStates ( cases , options ) {
65+ const states = [ ] ;
66+ for ( const [ test ] of cases ) {
67+ states . push ( test ( options ) ) ;
68+ }
69+ return states ;
70+ }
71+
5872 async onOpen ( ) {
59- this . options = Object . assign ( { } , DEFAULT_PLOT_OPTIONS ) ;
73+ this . options = JSON . parse ( JSON . stringify ( DEFAULT_PLOT_OPTIONS ) ) ; // deepcopy to avoid side effects
6074
6175 const { contentEl } = this ;
6276 contentEl . empty ( ) ;
@@ -102,26 +116,29 @@ export default class CreatePlotModal extends Modal {
102116 } ) ;
103117 } ) ;
104118
105- new Setting ( settings )
106- . setName ( "Bounds" )
107- . setDesc ( "Bounds must be written in this format: minX, maxX, minY, maxY." )
108- . addText ( ( text ) => {
109- text . setPlaceholder ( DEFAULT_PLOT_OPTIONS . bounds . join ( ", " ) ) ;
110- text . onChange ( async ( ) => {
111- let bounds = text
112- . getValue ( )
113- . split ( "," )
114- . map ( ( c ) => parseFloat ( c ) ) ;
115- const n = bounds . filter ( ( v ) => ! isNaN ( v ) ) . length ;
116- if ( n === 0 ) {
117- bounds = DEFAULT_PLOT_OPTIONS . bounds ;
118- }
119- if ( n >= 4 || n === 0 ) {
120- this . options . bounds = bounds as PlotOptions [ "bounds" ] ;
121- this . reloadPreview ( ) ;
122- }
123- } ) ;
119+ const placeholders = [ "X min" , "X max" , "Y min" , "Y max" ] ;
120+
121+ const bounds = new Setting ( settings ) . setName ( "Bounds" ) ;
122+
123+ placeholders . forEach ( ( placeholder , i ) => {
124+ bounds . addText ( ( text ) => {
125+ text
126+ . setPlaceholder ( placeholder )
127+ . onChange ( ( value ) => {
128+ if ( value && ! isNaN ( + value ) ) {
129+ this . options . bounds [ i ] = + value ;
130+ this . reloadPreview ( ) ;
131+ } else {
132+ console . log (
133+ `resetting ${ i } to default ${ DEFAULT_PLOT_OPTIONS . bounds [ i ] } `
134+ ) ;
135+ this . options . bounds [ i ] = DEFAULT_PLOT_OPTIONS . bounds [ i ] ;
136+ this . reloadPreview ( ) ;
137+ }
138+ } )
139+ . inputEl . classList . add ( "function-plot-numberinput" ) ;
124140 } ) ;
141+ } ) ;
125142
126143 new Setting ( settings ) . setName ( "Disable Zoom" ) . addToggle ( ( com ) => {
127144 com . setValue ( this . options . disableZoom ) ;
@@ -139,21 +156,48 @@ export default class CreatePlotModal extends Modal {
139156 } ) ;
140157 } ) ;
141158
142- new Setting ( settings )
159+ const functionsSetting = new Setting ( settings )
143160 . setName ( "Functions" )
144- . setDesc (
145- "Specify functions to plot. Must be in format: <name>(x) = <expression>."
146- )
147- . addTextArea ( ( com ) => {
148- com . onChange ( async ( value ) => {
149- if ( ! value . trim ( ) ) return ;
150- this . options . functions = value
151- . split ( "\n" )
152- . map ( ( f ) => f . trim ( ) || undefined ) ;
153- // maybe check if there are valid functions
154- this . reloadPreview ( ) ;
161+ . setDesc ( "Functions to plot." ) ;
162+ functionsSetting . settingEl . setAttribute ( "style" , "display: block" ) ;
163+ const functionsControlEl = functionsSetting . controlEl ;
164+ functionsControlEl . classList . value = "function-plot-functions-container" ;
165+ const functionsList = functionsControlEl . createDiv ( {
166+ attr : { class : "function-plot-functions-list" } ,
167+ } ) ;
168+
169+ functionsControlEl . createDiv (
170+ { attr : { class : "function-plot-functions-add" } } ,
171+ ( el ) => {
172+ new Setting ( el ) . addButton ( ( btn ) => {
173+ btn
174+ . setButtonText ( "Add function" )
175+ . setIcon ( "plus" )
176+ . onClick ( async ( ) => {
177+ const id = Math . random ( ) . toString ( 36 ) . substring ( 2 , 9 ) ;
178+ const options = Object . assign (
179+ JSON . parse ( JSON . stringify ( DEFAULT_FUNCTION_OPTIONS ) ) ,
180+ { id }
181+ ) ;
182+ const prevStates = this . computeStates ( FUNCTION_CASES , options ) ;
183+
184+ new Setting ( functionsList ) . addDropdown ( ( com ) => {
185+ com
186+ . addOptions ( {
187+ linear : "linear" ,
188+ vector : "vector" ,
189+ polar : "polar" ,
190+ points : "points" ,
191+ } )
192+ . setValue ( options . fnType )
193+ . onChange ( ( value ) => {
194+ options . fnType = value ;
195+ } ) ;
196+ } ) ;
197+ } ) ;
155198 } ) ;
156- } ) ;
199+ }
200+ ) ;
157201
158202 new Setting ( contentEl )
159203 /*.addDropdown((com) => {
@@ -169,12 +213,12 @@ export default class CreatePlotModal extends Modal {
169213 . setButtonText ( "Plot" )
170214 . setCta ( )
171215 . onClick ( async ( ) => {
172- await this . handlePlotCreate ( this . options ) ;
216+ await this . handleFinalPlotCreate ( this . options ) ;
173217 } ) ;
174218 } ) ;
175219 }
176220
177- async handlePlotCreate ( options : PlotOptions ) {
221+ async handleFinalPlotCreate ( options : PlotOptions ) {
178222 // render and insert chosen plot using renderer
179223 switch ( this . renderer ) {
180224 case "interactive" :
0 commit comments