LCOV - code coverage report
Current view: top level - src/store/modules - engine.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 45 60 75.0 %
Date: 2025-06-29 02:18:36 Functions: 12 17 70.6 %

          Line data    Source code
       1             : // @ts-check
       2             : 
       3             : import Vue from "vue";
       4             : import { SSVGEngine } from "@cern/ssvg-engine";
       5             : import { find, forEach, get } from "lodash";
       6             : import { getDomSelectors } from "../../utils";
       7             : 
       8             : /** @type {V.Module<AppStore.SSVGEngine>} */
       9           1 : const mod = {
      10             :   namespaced: true,
      11           1 :   state: () => ({
      12             :     text: null, // complete svg as text
      13             :     fragment: null, // complete svg as Node tree
      14             :     engine: null, // SSVG engine
      15             :     state: null, // current ssvg state
      16             :     stateMin: null, // min values for states (auto type support)
      17             :     stateMax: null, // max values for states (auto type support)
      18             :     directEngine: null, // SSVG engine with no animations
      19             :     stateElements: null, // state elements list
      20             :     svgSelectors: null /* possible selectors for the document */
      21             :   }),
      22             :   getters: {
      23             :     svgSelectorsSet(state) {
      24           0 :       return new Set(state.svgSelectors);
      25             :     }
      26             :   },
      27             :   mutations: {
      28             :     /**
      29             :      * @param {AppStore.SSVGEngine} state
      30             :      */
      31             :     release(state) {
      32           0 :       if (state.engine) {
      33           0 :         state.engine.disconnect();
      34             :       }
      35           0 :       if (state.directEngine) {
      36           0 :         state.directEngine.disconnect();
      37             :       }
      38           0 :       forEach(state, (s, name) => {
      39           0 :         Vue.set(state, name, null);
      40             :       });
      41             :     },
      42             :     /**
      43             :      * @brief update the engine state
      44             :      * @param {AppStore.SSVGEngine} state
      45             :      * @param {any} value
      46             :      */
      47             :     updateState(state, value) {
      48           9 :       if (state.engine) {
      49           8 :         state.engine.updateState(value);
      50           8 :         mod?.mutations?.updateMinMax(state, value);
      51             :         /* update computed properties */
      52           8 :         state.state = state.engine.getState();
      53             :       }
      54           9 :       if (state.directEngine) {
      55           8 :         state.directEngine.updateState(value);
      56             :       }
      57             :     },
      58             :     /**
      59             :      * @brief set an new engine
      60             :      * @param {AppStore.SSVGEngine} state
      61             :      * @param {any} engine
      62             :      */
      63             :     updateEngine(state, engine) {
      64           5 :       state.engine?.disconnect();
      65           5 :       state.directEngine?.disconnect();
      66             : 
      67           5 :       state.fragment = engine.fragment;
      68           5 :       state.text = state.fragment?.outerHTML ?? null;
      69           5 :       state.engine = engine.engine;
      70           5 :       state.directEngine = engine.directEngine;
      71           5 :       state.svgSelectors = getDomSelectors(get(state.engine, [ "svg" ]));
      72           5 :       state.stateElements = state.engine.svg.getElementsByTagName("state");
      73           5 :       state.stateMin = null;
      74           5 :       state.stateMax = null;
      75           5 :       state.state = state.engine.getState();
      76             :     },
      77             :     /**
      78             :      * @brief update min/max values
      79             :      * @param {AppStore.SSVGEngine} state
      80             :      * @param {any} value
      81             :      * @details used to keep track of min/max for "auto" variables
      82             :      */
      83             :     updateMinMax(state, value) {
      84           8 :       state.stateMin = state.stateMin ?? {};
      85           8 :       state.stateMax = state.stateMax ?? {};
      86           8 :       forEach(value, (v, k) => {
      87          23 :         if (typeof v === "number") {
      88           8 :           if (v > (state.stateMax[k] ?? 1)) {
      89           3 :             state.stateMax[k] = v;
      90             :           }
      91           5 :           else if (v < (state.stateMin[k] ?? 0)) {
      92           0 :             state.stateMin[k] = v;
      93             :           }
      94             :         }
      95             :         else {
      96          15 :           state.stateMin[k] = state.stateMax[k] = null;
      97             :         }
      98             :       });
      99             :     }
     100             :   },
     101             :   actions: {
     102             :     /**
     103             :      * @param {string} text
     104             :      */
     105             :     async load(context, text) {
     106           5 :       return Promise.resolve()
     107             :       .then(() => {
     108           5 :         var frag = document.createRange().createContextualFragment(text);
     109           5 :         if (!frag) { throw "invalid XML"; }
     110             : 
     111           5 :         const element = find(frag.children, { nodeName: "svg" });
     112           5 :         if (!element || (element.nodeName !== "svg")) {
     113           0 :           throw new Error("not an SVG document");
     114             :         }
     115           5 :         return context.dispatch("loadFragment", element);
     116             :       });
     117             :     },
     118             :     /**
     119             :      * @param  {Element} element
     120             :      */
     121             :     async loadFragment(context, element) {
     122           6 :       const oldState = context.state.state;
     123           6 :       return Promise.resolve()
     124             :       .then(() => {
     125           6 :         const fragStates = element.getElementsByTagName("state");
     126           6 :         if (fragStates.length === 0) {
     127           0 :           element.insertBefore(
     128             :             document.createElementNS("http://www.w3.org/2000/svg", "state"),
     129             :             element.firstChild);
     130             :         }
     131             : 
     132           6 :         const engine = new SSVGEngine(/** @type {Element} */(element.cloneNode(true)));
     133             : 
     134           5 :         const directElement = /** @type {Element} */ (element.cloneNode(true));
     135           5 :         directElement.querySelectorAll("state transition").forEach((item) => {
     136           3 :           item.setAttribute("duration", "0");
     137           3 :           item.setAttribute("delay", "0");
     138             :         });
     139           5 :         return {
     140             :           fragment: Object.freeze(element),
     141             :           engine: Object.freeze(engine),
     142             :           directEngine: Object.freeze(new SSVGEngine(directElement))
     143             :         };
     144             :       })
     145           5 :       .then((value) => context.commit("updateEngine", value))
     146             :       .then(() => {
     147           5 :         if (oldState) { context.commit("updateState", oldState); }
     148             :       });
     149             :     },
     150             :     async reload(context) {
     151           0 :       const oldState = context.state.state;
     152           0 :       await context.dispatch("loadFragment", context.state.fragment);
     153           0 :       context.commit("updateState", oldState);
     154             :     },
     155             :     async init(context) {
     156           0 :       if (context.state.text) {
     157           0 :         return context.dispatch("load", context.state.text);
     158             :       }
     159             :     }
     160             :   }
     161             : };
     162             : export default mod;

Generated by: LCOV version 1.16