Browse Source

initial autocomplete and autoevaluate

Konstantin Ladutenko 3 years ago
parent
commit
353d001dd7

+ 122 - 9
guiapp/package-lock.json

@@ -10,6 +10,7 @@
         "@quasar/extras": "^1.0.0",
         "@types/emscripten": "^1.39.5",
         "core-js": "^3.6.5",
+        "mathjs": "^9.5.0",
         "quasar": "^2.0.0",
         "vuex": "^4.0.1"
       },
@@ -1642,7 +1643,6 @@
       "version": "7.15.4",
       "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz",
       "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==",
-      "dev": true,
       "dependencies": {
         "regenerator-runtime": "^0.13.4"
       },
@@ -3962,6 +3962,18 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/complex.js": {
+      "version": "2.0.15",
+      "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.0.15.tgz",
+      "integrity": "sha512-gDBvQU8IG139ZBQTSo2qvDFP+lANMGluM779csXOr6ny1NUtA3wkUnCFjlDNH/moAVfXtvClYt6G0zarFbtz5w==",
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "type": "patreon",
+        "url": "https://www.patreon.com/infusion"
+      }
+    },
     "node_modules/compress-commons": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz",
@@ -4745,6 +4757,11 @@
         }
       }
     },
+    "node_modules/decimal.js": {
+      "version": "10.3.1",
+      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz",
+      "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ=="
+    },
     "node_modules/decompress-response": {
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
@@ -5520,6 +5537,11 @@
       "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
       "dev": true
     },
+    "node_modules/escape-latex": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz",
+      "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw=="
+    },
     "node_modules/escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -6677,7 +6699,6 @@
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.1.tgz",
       "integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==",
-      "dev": true,
       "engines": {
         "node": "*"
       },
@@ -7963,6 +7984,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/javascript-natural-sort": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
+      "integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k="
+    },
     "node_modules/javascript-stringify": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz",
@@ -8609,6 +8635,28 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/mathjs": {
+      "version": "9.5.0",
+      "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-9.5.0.tgz",
+      "integrity": "sha512-a6QFEoLFLEI1cKr0B7lwAM1TTNAfNTxppimyqS5WhxGKXbV59DK4OX606z05PpuKpTiq7gTtPiSV0OAwFfxSvw==",
+      "dependencies": {
+        "@babel/runtime": "^7.15.4",
+        "complex.js": "^2.0.15",
+        "decimal.js": "^10.3.1",
+        "escape-latex": "^1.2.0",
+        "fraction.js": "^4.1.1",
+        "javascript-natural-sort": "^0.7.1",
+        "seedrandom": "^3.0.5",
+        "tiny-emitter": "^2.1.0",
+        "typed-function": "^2.0.0"
+      },
+      "bin": {
+        "mathjs": "bin/cli.js"
+      },
+      "engines": {
+        "node": ">= 12"
+      }
+    },
     "node_modules/mdn-data": {
       "version": "2.0.14",
       "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
@@ -10831,8 +10879,7 @@
     "node_modules/regenerator-runtime": {
       "version": "0.13.9",
       "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
-      "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
-      "dev": true
+      "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
     },
     "node_modules/regenerator-transform": {
       "version": "0.14.5",
@@ -11358,6 +11405,11 @@
         "url": "https://opencollective.com/webpack"
       }
     },
+    "node_modules/seedrandom": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
+      "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
+    },
     "node_modules/select-hose": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -12179,6 +12231,11 @@
       "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
       "dev": true
     },
+    "node_modules/tiny-emitter": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
+      "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
+    },
     "node_modules/tmp": {
       "version": "0.0.33",
       "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -12461,6 +12518,14 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/typed-function": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-2.0.0.tgz",
+      "integrity": "sha512-Hhy1Iwo/e4AtLZNK10ewVVcP2UEs408DS35ubP825w/YgSBK1KVLwALvvIG4yX75QJrxjCpcWkzkVRB0BwwYlA==",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
     "node_modules/typedarray": {
       "version": "0.0.6",
       "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
@@ -14746,7 +14811,6 @@
       "version": "7.15.4",
       "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz",
       "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==",
-      "dev": true,
       "requires": {
         "regenerator-runtime": "^0.13.4"
       }
@@ -16624,6 +16688,11 @@
       "integrity": "sha1-AWLsLZNR9d3VmpICy6k1NmpyUIA=",
       "dev": true
     },
+    "complex.js": {
+      "version": "2.0.15",
+      "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.0.15.tgz",
+      "integrity": "sha512-gDBvQU8IG139ZBQTSo2qvDFP+lANMGluM779csXOr6ny1NUtA3wkUnCFjlDNH/moAVfXtvClYt6G0zarFbtz5w=="
+    },
     "compress-commons": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz",
@@ -17197,6 +17266,11 @@
         "ms": "2.1.2"
       }
     },
+    "decimal.js": {
+      "version": "10.3.1",
+      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz",
+      "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ=="
+    },
     "decompress-response": {
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
@@ -17824,6 +17898,11 @@
       "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
       "dev": true
     },
+    "escape-latex": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz",
+      "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw=="
+    },
     "escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -18698,8 +18777,7 @@
     "fraction.js": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.1.tgz",
-      "integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==",
-      "dev": true
+      "integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg=="
     },
     "fresh": {
       "version": "0.5.2",
@@ -19674,6 +19752,11 @@
       "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
       "dev": true
     },
+    "javascript-natural-sort": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
+      "integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k="
+    },
     "javascript-stringify": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz",
@@ -20210,6 +20293,22 @@
         }
       }
     },
+    "mathjs": {
+      "version": "9.5.0",
+      "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-9.5.0.tgz",
+      "integrity": "sha512-a6QFEoLFLEI1cKr0B7lwAM1TTNAfNTxppimyqS5WhxGKXbV59DK4OX606z05PpuKpTiq7gTtPiSV0OAwFfxSvw==",
+      "requires": {
+        "@babel/runtime": "^7.15.4",
+        "complex.js": "^2.0.15",
+        "decimal.js": "^10.3.1",
+        "escape-latex": "^1.2.0",
+        "fraction.js": "^4.1.1",
+        "javascript-natural-sort": "^0.7.1",
+        "seedrandom": "^3.0.5",
+        "tiny-emitter": "^2.1.0",
+        "typed-function": "^2.0.0"
+      }
+    },
     "mdn-data": {
       "version": "2.0.14",
       "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
@@ -21814,8 +21913,7 @@
     "regenerator-runtime": {
       "version": "0.13.9",
       "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
-      "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
-      "dev": true
+      "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
     },
     "regenerator-transform": {
       "version": "0.14.5",
@@ -22189,6 +22287,11 @@
         "ajv-keywords": "^3.5.2"
       }
     },
+    "seedrandom": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
+      "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
+    },
     "select-hose": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -22858,6 +22961,11 @@
       "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
       "dev": true
     },
+    "tiny-emitter": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
+      "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
+    },
     "tmp": {
       "version": "0.0.33",
       "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -23062,6 +23170,11 @@
         "mime-types": "~2.1.24"
       }
     },
+    "typed-function": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-2.0.0.tgz",
+      "integrity": "sha512-Hhy1Iwo/e4AtLZNK10ewVVcP2UEs408DS35ubP825w/YgSBK1KVLwALvvIG4yX75QJrxjCpcWkzkVRB0BwwYlA=="
+    },
     "typedarray": {
       "version": "0.0.6",
       "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",

+ 1 - 0
guiapp/package.json

@@ -13,6 +13,7 @@
     "@quasar/extras": "^1.0.0",
     "@types/emscripten": "^1.39.5",
     "core-js": "^3.6.5",
+    "mathjs": "^9.5.0",
     "quasar": "^2.0.0",
     "vuex": "^4.0.1"
   },

+ 131 - 58
guiapp/src/components/CompositionComponent.vue

@@ -1,83 +1,99 @@
 <template>
   <div>
     <q-card
-            flat
-            bordered
+        bordered
+        flat
     >
-      <q-tooltip v-if="tooltipText">
-        {{tooltip_text}}
-      </q-tooltip>
       <q-card-section
-          horizontal
-          class="items-center bg-grey-2">
-        <div class="side_note text-grey-9 q-px-xs"
+          class="items-center bg-grey-2"
+          horizontal>
+        <div v-if='title' class="side_note text-grey-9 q-px-xs"
              style="width: 4rem"
         >
-          {{title}}
+          {{ title }}
         </div>
+        <div
+            @mousemove="setTooltip"
+        >
+
+        <q-tooltip
+            v-model = "isShowingTooltip"
+                   anchor="top middle"
+                   self="center middle"
+        >
+          = {{round_number(localTooltipText,5)}}
+        </q-tooltip>
 
         <q-select
-            :model-value="name"
-            @input-value="$emit('update:name', $event)"
-            use-input
-            hide-selected
-            fill-input
-            input-debounce="0"
+            :model-value="localQSelectValue"
             :options="options"
-            style="width: 10rem"
-            options-dense
-            dense
             bg-color="white"
             class="q-py-none"
+            dense
+            fill-input
+            hide-selected
+            input-debounce="0"
+            options-dense
+            style="width: 10rem"
+            use-input
+            behavior="menu"
+            @focus="setTooltip"
+            @blur="handleQSelectBlur"
+            @keydown.enter="handleQSelectBlur"
+            @keydown.tab="handleQSelectBlur"
+            @input-value="localQSelectValue=$event"
         >
-          <template v-slot:no-option>
-            <q-item>
-              <q-item-section class="text-grey">
-                No results
-              </q-item-section>
-            </q-item>
+          <template
+                    v-if="localTooltipText&&!isShowingTooltip"
+                    #append
+          >
+            <div
+                style="font-size: 12px"
+            >
+              ={{round_number(localTooltipText,1)}}
+            </div>
           </template>
+<!--          <template #no-option>-->
+<!--            <q-item>-->
+<!--              <q-item-section class="text-grey">-->
+<!--                No results-->
+<!--              </q-item-section>-->
+<!--            </q-item>-->
+<!--          </template>-->
         </q-select>
+        </div>
 
         <div
             class="side_note text-grey-9 q-px-xs"
             style="width: 3rem"
         >
-          {{ units}}
+          {{ units }}
         </div>
       </q-card-section>
     </q-card>
-    local options: {{name}}
+<!--    local options: {{ inputValue }}-->
+
+    local: {{localQSelectValue}}
   </div>
 </template>
 
 <script lang="ts">
 // import { useModelWrapper } from 'components/modelWrapper'
-import {
-  defineComponent,
-  //   watch,
-  // PropType,
-  // computed,
+import {evaluate, isNumeric} from 'mathjs';
+import {defineComponent,
   ref,
-  // toRef,
-  // Ref,
-} from 'vue';
-// import { Todo, Meta } from './models';
-
-// function useModelWrapper(props, emit, name = 'modelValue') {
-//   return computed({
-//     get: () => props[name],
-//     set: (value) => emit(`update:${name}`, value)
-//   })
-// }
-const stringOptions = [
-  'Google', 'Facebook', 'Twitter', 'Apple', 'Oracle'
-]
+  watch,
+  onMounted,
+  } from 'vue';
 
 export default defineComponent({
   name: 'InputWithUnits',
   props: {
-    name: {
+    outputValue: {
+      type: Number,
+      default: 0
+    },
+    evalExpr: {
       type: String,
       default: ''
     },
@@ -87,7 +103,7 @@ export default defineComponent({
       default: ''
     },
     units: {
-      type:String,
+      type: String,
       default: ''
     },
     tooltipText: {
@@ -95,20 +111,77 @@ export default defineComponent({
       default: ''
     }
   },
-  emits : [
-    'update:name'
+  emits: [
+    'update:output-value'
+    // <!--            @input-value="$emit('update:input-expr', $event)"-->
+    // <!--        >-->
   ],
   setup(props, {emit}) {
-  //   // import { ref } from 'vue'
-  //   // const return_value = ref(0)
-  //   // var options = ref([3, 2])
-    const options = ref(stringOptions)
-  //   // var return_value = ref(null)
-  //   var model = ref(null)
-    return {
-  //     model,
-      options
+    let localQSelectValue = ref('')
+    let localTooltipText = ref('')
+    let isShowingTooltip = ref(false)
+
+
+    onMounted(()=>{
+      localQSelectValue.value = props.evalExpr
+      localTooltipText.value = props.evalExpr
+      if (props.tooltipText) localTooltipText.value = props.tooltipText
+      console.log(localTooltipText.value)
+    });
+
+
+    let options = ref(['1+2', 'sqrt(6)*20'])
+    let evaluatedValue = ref(0)
+
+
+    function setTooltip(){
+      if (evaluatedValue.value != Number(localQSelectValue.value)) {
+        localTooltipText.value = evaluatedValue.value.toString()
+        isShowingTooltip.value = true
+      } else {
+        localTooltipText.value = ''
+        isShowingTooltip.value = false
+      }
+    }
+
+
+    function handleQSelectBlur(){
+      isShowingTooltip.value=false
+      const expr = localQSelectValue.value
+      if (!options.value.includes(expr)) options.value.unshift(expr);
+      if (options.value.length > 5) options.value.pop();
+      // localQSelectValue.value = evaluatedValue.value.toString()
+    }
+
+
+    function round_number (value:string, digits:number):number {
+      // TODO manage special cases of very big and very
+      // small numbers assuming digits value is small
+      return Number(Math.round(parseFloat(value + 'e' + digits.toString())) + 'e-' + digits.toString())
     }
+
+
+    watch(localQSelectValue, () => {
+      let tryEvaluate:any
+      try {
+        tryEvaluate = evaluate(localQSelectValue.value)
+        if (isNumeric(tryEvaluate)) evaluatedValue.value = Number(tryEvaluate)
+      } catch { }
+    })
+
+
+
+
+    watch(evaluatedValue, () => {
+      emit('update:output-value', evaluatedValue.value)
+      setTooltip()
+    })
+
+
+    return {
+      options,  localQSelectValue, localTooltipText, isShowingTooltip,
+      setTooltip, handleQSelectBlur, round_number
+    };
   },
 });
 </script>

+ 8 - 5
guiapp/src/pages/Index.vue

@@ -2,13 +2,14 @@
   <q-page class="row items-center justify-evenly">
 
     <input-with-units
-        v-model:name="name"
+        v-model:output-value="someValue"
+        v-model:eval-expr="someExpr"
+        v-model:is-show-help="isShowHelp"
         title="Re(n)"
         units="nm"
-        tooltip_text="help text"
         active
     ></input-with-units>
-    Input result: {{name}}
+    Input result: {{someValue}}
 <!--    tooltip_text="help text"-->
   </q-page>
 </template>
@@ -22,8 +23,10 @@ export default defineComponent({
   name: 'PageIndex',
   components: {InputWithUnits },
   setup() {
-    let name = ref('')
-    return {name};
+    let someValue = ref(10);
+    let someExpr = ref('10');
+    let isShowHelp = ref(true)
+    return { someValue, someExpr, isShowHelp };
   }
 });
 </script>