首页 > 解决方案 > 如何在 amCharts 中调用 am4core 之前加载库?

问题描述

我有一个要求,我必须使用 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中的日志以了解我面临的问题。

提前致谢。

标签: javascripthtmlcssweb-componentamcharts

解决方案


我从Promise.all开始,但最终遇到了Amcharts需要按顺序加载的问题。

ES7 等待将完成这项工作

您已经完成了一半,但停止了 async 部分并继续使用 sync 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);
      });
    }
  });

})();
<my-element></my-element>

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

  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/


推荐阅读