【问题标题】:How to load libraries before am4core is called in amCharts?如何在 amCharts 中调用 am4core 之前加载库?
【发布时间】:2020-08-01 19:14:10
【问题描述】:

我有一个要求,我必须使用 Amcharts 创建自定义小部件。但我面临的问题是在加载库之前调用 am4core 函数。

HTML 代码

<com-sap-sample-helloworld5></com-sap-sample-helloworld5>

js代码


(function () {
  const amchartscorejs = "https://www.amcharts.com/lib/4/core.js";
  const amchartschartsjs = "https://www.amcharts.com/lib/4/charts.js";
  const amchartsanimatedjs = "https://www.amcharts.com/lib/4/themes/animated.js";
  const vennchartjs = "https://cdn.amcharts.com/lib/4/plugins/venn.js";
  async function LoadLibs() {
    console.log("LoadLibs");
    try {
      await loadScript(amchartscorejs);
      await loadScript(amchartschartsjs);
      await loadScript(amchartsanimatedjs);
      await loadScript(vennchartjs);
    } catch (e) {
      alert(e);
    } finally {
      that._firstConnection = 1;
    }
  }
  LoadLibs();
  function loadScript(src) {
    console.log("LoadScript");
    return new Promise(function (resolve, reject) {
      let script = document.createElement("script");
      script.src = src;
      script.onload = () => {
        console.log("Load: " + src);
        resolve(script);
      };
      script.onerror = () => reject(new Error(`Script load error for ${src}`));
      document.head.appendChild(script);
    });
  }
  let template = document.createElement("template");
  template.innerHTML = `<div id="chartdiv" width="100%" height="500px"></div>`;
  customElements.define(
    "com-sap-sample-helloworld5",
    class HelloWorld extends HTMLElement {
      constructor() {
        super();
        let shadowRoot = this.attachShadow({
          mode: "open",
        });
        shadowRoot.appendChild(template.content.cloneNode(true));
        this._firstConnection = false;
        this.addEventListener("click", (event) => {
          var event = new Event("onClick");
          this.dispatchEvent(event);
        });
      }
      //Fired when the widget is added to the html DOM of the page
      connectedCallback() {
        this._firstConnection = true;
        this.redraw();
      }
      //Fired when the widget is removed from the html DOM of the page (e.g. by hide)
      disconnectedCallback() {}
      //When the custom widget is updated, the Custom Widget SDK framework executes this function first
      onCustomWidgetBeforeUpdate(oChangedProperties) {}
      //When the custom widget is updated, the Custom Widget SDK framework executes this function after the update
      onCustomWidgetAfterUpdate(oChangedProperties) {
        if (this._firstConnection) {
          this.redraw();
        }
      }
      //When the custom widget is removed from the canvas or the analytic application is closed
      onCustomWidgetDestroy() {}
      //When the custom widget is resized on the canvas, the Custom Widget SDK framework executes the following JavaScript function call on the custom widget
      // Commented out by default
      /*
    onCustomWidgetResize(width, height){
    
    }
    */
      get chartType() {
        return this.chartTypeValue;
      }
      set chartType(value) {
        this.chartTypeValue = value;
      }

      redraw() {
        console.log("redraw function");
        // Themes begin
        am4core.useTheme(am4themes_animated);
        // Themes end
        var data = [
          { name: "A", value: 10 },
          {
            name: "B",
            value: 10,
          },
          {
            name: "C",
            value: 10,
          },
          {
            name: "X",
            value: 2,
            sets: ["A", "B"],
          },
          {
            name: "Y",
            value: 2,
            sets: ["A", "C"],
          },
          {
            name: "Z",
            value: 2,
            sets: ["B", "C"],
          },
          {
            name: "Q",
            value: 1,
            sets: ["A", "B", "C"],
          },
        ];

        var chart = am4core.create("chartdiv", am4plugins_venn.VennDiagram);
        var series = chart.series.push(new am4plugins_venn.VennSeries());
        series.dataFields.category = "name";
        series.dataFields.value = "value";
        series.dataFields.intersections = "sets";
        series.data = data;
        chart.legend = new am4charts.Legend();
        chart.legend.marginTop = 40;
      }
    }
  );
})();


请告诉我应该做哪些更改,以便首先加载 amCharts 库,然后调用 redraw() 函数。

您也可以查看jsfiddle 中的日志以了解我面临的问题。

提前致谢。

【问题讨论】:

    标签: javascript html css web-component amcharts


    【解决方案1】:

    我从Promise.all 开始,但最终以Amcharts Issue 结束,Amcharts 需要按顺序加载。

    ES7 等待将完成这项工作

    您已经完成了一半,但停止了异步部分并继续同步loadLibs,看起来您在加载完成后尝试标记元素。

    这里的库是按顺序加载的,带有一个通用的 loadScripts 函数,
    准备好多个自定义元素,具体取决于 AmCharts,脚本只会加载一次:

    (function() {
      function log() {
        let args = [...arguments];
        //console.log(`%c ${args.shift()} `, "background:lightgreen", ...args); //Chrome!
        document.body.append(args.join` `,document.createElement('BR'));
      }
      log("start IIFE script");
      async function loadScripts() {
        const load = (src) => new Promise((resolve, reject) => {
          const script = document.createElement('script');
          script.src = `https://www.amcharts.com/lib/4/${src}.js`;
          if (document.querySelector(`[src="${script.src}"]`)) resolve();
          log("load", script.src)
          script.onload = resolve;
          //script.onerror = () => reject(new Error(`Script load error for ${src}`));
          document.head.append(script)
        });
        await load("core"); // must be loaded first
        await load("charts");
        await load("themes/animated");
        await load("plugins/venn");
        return "return not even required";
      }
      customElements.define('my-element', class extends HTMLElement {
        connectedCallback() {
          this.attachShadow({mode: "open"}).innerHTML = `<div>Executing:</div>`;
          log('connectedCallback');
          loadScripts().then(result => {
            log('done loading', result);
          });
        }
      });
    
    })();
    &lt;my-element&gt;&lt;/my-element&gt;

    您可以移动 内部(现在标记为 async)connectedCallback 的所有内容

      async connectedCallback() {
        const load = (src) => new Promise((resolve, reject) => {
          let script = document.createElement('script');
          script.src = `https://www.amcharts.com/lib/4/${src}.js`;
          //if (document.querySelector(`[src="${script.src}"]`)) resolve();
          script.onload = resolve;
          this.append(script); // fine, doesn't really matter where SCRIPT is injected
        });
        await load("core");
        await load("charts");
        await load("themes/animated");
        await load("plugins/venn");
        // Loaded all
      }
    
    

    如果 connectedCallback 运行多次,因为你移动了 DOM 节点,你需要检查已经加载的脚本

    JSFiddle 中的以上代码:https://jsfiddle.net/CustomElementsExamples/wz79gbum/

    【讨论】:

      【解决方案2】:

      将您正在触发 am4core 的代码的一部分移动到单独的文件并像其他文件一样加载它,但也将您的 loadScript 函数更改为使用 defer:

       function loadScript(src)
      {
      console.log("LoadScript");
        return new Promise(function(resolve, reject) 
      {
          let script = document.createElement('script');
          script.src = src;
          script.defer = true;
      
          script.onload = () => {console.log("Load: " + src); resolve(script);}
          script.onerror = () => reject(new Error(`Script load error for ${src}`));
      
          document.head.appendChild(script)
        });
      }
      

      顺便说一句,我认为将标签放在一起总是更好,所以更改最后一行:

      document.head.appendChild(script)
      

      到:

      var scriptTag = document.head.getElementsByTagName('script')[0];
      scriptTag.parentNode.insertBefore(script, scriptTag.nextSibling);
      

      【讨论】:

      • “最好将标签放在一起” 仅适用于那些打开 F12 HTML Source 的人。您注入script 在哪里 并不重要。您可以执行document.body.append(script) 并获得相同的功能结果。只有在注入 CSS 时,顺序才是重要的。您的 getElementsByTagName 使用实际上使情况变得更糟,它创建了一个 live nodeList;您没有清除变量,因此浪费了 CPU 周期。
      猜你喜欢
      • 1970-01-01
      • 2018-11-17
      • 1970-01-01
      • 2021-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多