🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

ECharts 萬字入門指南

ECharts

同步至個人站點:ECharts 萬字入門指南

039.png

ECharts 萬字入門指南

本文將作為你的 ECharts 入門指南,帶你系統性地梳理 ECharts 的核心知識體系,並透過一個貼近實際業務的“高三期末考試成績分析”案例,手把手教你如何將數據轉化為富有洞察力的圖表。

前端,本質上就是把數據可視化的技術。如何將枯燥的數據,以一種更直觀、更易於理解的方式呈現給用戶,始終是一個重要的課題。

圖表,無疑是這個問題的最佳答案之一。

小到健康 App 中記錄一周睡眠變化的柱狀圖,大到金融應用的實時股票儀表板,圖表作為一種強大的視覺語言,其傳遞信息的效率遠超純粹的文字或表格。它能幫助我們快速發現數據中的模式、趨勢和異常點。

在眾多選擇中,Apache ECharts 無疑是當下最閃耀的產品之一。憑藉其豐富的圖表類型、強大的交互功能、靈活的配置項以及活躍的社區,成為了全球前端開發者的首選。

然而,和 GSAP 動畫庫 一樣,很多人對 ECharts 的第一印象是“配置項繁多”、“學習曲線陡峭”。但事實果真如此嗎?

當我們靜下心來,深入探索 ECharts 的世界,會發現其核心概念並不複雜。萬變不離其宗,所有的圖表配置,都圍繞著一些固定的核心模塊展開:容器與大小、樣式、數據集、坐標軸、視覺映射、圖例等等。

ECharts 官網提供了海量的示例,幾乎涵蓋了你能想到的所有圖表效果。甚至,它的配置項文檔本身就是可交互的——你可以一邊修改配置,一邊實時預覽效果。這極大地降低了學習門檻。

043.png

ECharts 初體驗:繪製你的第一個圖表

學習任何一門技術的最好方式,就是從一個“Hello World”開始。

引入方式

我們將使用最簡單的方式:通過 CDN 引入。你只需要在 HTML 文件中加入一個 <script> 標籤即可。這種方式無需構建工具,非常適合快速原型開發和學習。

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>

完整示例

將下面的代碼完整複製到一個 HTML 文件中,然後用瀏覽器打開它,你就能看到你的第一個 ECharts 圖表了。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>ECharts 入門示例</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
  </head>
  <body>
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
      // 3. 基於準備好的dom,初始化echarts實例
      var myChart = echarts.init(document.getElementById("main"));

      // 4. 指定圖表的配置項和數據
      var option = {
        // 標題
        title: {
          text: "我的第一個 ECharts 圖表",
        },
        // 提示框
        tooltip: {},
        // X 軸
        xAxis: {
          data: ["襯衫", "羊毛衫", "雪紡衫", "褲子", "高跟鞋", "襪子"],
        },
        // Y 軸
        yAxis: {},
        // 系列(系列決定了圖表類型和數據)
        series: [
          {
            name: "銷量",
            type: "bar", // 'bar' 表示這是一個柱狀圖
            data: [5, 20, 36, 10, 10, 20],
          },
        ],
      };

      // 5. 使用剛指定的配置項和數據顯示圖表。
      myChart.setOption(option);
    </script>
  </body>
</html>

044.png

這個簡單的例子,已經揭示了 ECharts 的核心工作流程:引入腳本 -> 準備容器 -> 初始化實例 -> 設置配置項。而所有 ECharts 圖表的實現,都蘊含在那個巨大的 option 對象中。

核心概念解析:解構 option 對象

ECharts 的 option 對象是一個龐大而複雜的 JavaScript 對象,option 描述了圖表的一切:數據、樣式、交互、動畫等等。理解了它的核心構成,就等於掌握了 ECharts 的精髓。

讓我們像剝洋蔥一樣,一層一層地解析 option 的核心組件。

series:系列與圖表類型

series 是 ECharts 中最重要的配置項,沒有之一。它是一個數組,數組中的每一個對象都代表一個“系列”。

什麼是“系列”?

你可以把它理解為一組相關的數據,以及這組數據如何被可視化的規則。一個圖表中可以包含多個系列,每個系列會按照自己的規則(即 type)繪製成圖。

比如,在上面的例子中:

series: [
  {
    name: "銷量",
    type: "bar", // 圖表類型
    data: [5, 20, 36, 10, 10, 20], // 系列數據
  },
],
  • type: 'bar' 告訴 ECharts,這個系列要繪製成柱狀圖。
  • data: [...] 提供了這組柱狀圖的具體數值。

如果我想在同一個圖表中,再增加一條折線圖來表示“產量”,只需在 series 數組中再增加一個對象即可。

series: [
  {
    name: "銷量",
    type: "bar",
    data: [5, 20, 36, 10, 10, 20],
  },
  {
    name: "產量",
    type: "line", // 圖表類型為折線圖
    data: [15, 25, 30, 18, 15, 30],
  },
],

ECharts 支持的圖表類型非常豐富,常見的有:

  • line: 折線圖
  • bar: 柱狀圖
  • pie: 餅圖
  • scatter: 散點圖
  • radar: 雷達圖
  • map: 地圖
  • tree: 樹圖
  • graph: 關係圖
  • ...等等

series 的強大之處在於,它不僅定義了圖表的“形”,更承載了圖表的“魂”——數據。

xAxis & yAxis:坐標軸

對於絕大多數圖表(如折線圖、柱狀圖、散點圖),坐標軸是必不可少的。ECharts 通過 xAxis (X 軸) 和 yAxis (Y 軸) 來進行配置。它們通常成對出現,共同定義了一個直角坐標系 (Grid)

坐標軸主要由軸線、刻度、刻度標籤、軸名稱等部分組成。

一個常見的 xAxis 配置如下:

xAxis: {
  type: 'category', // 坐標軸類型
  data: ['一月', '二月', '三月', '四月', '五月'], // 類目數據
  name: '月份', // 軸名稱
  axisLine: { show: true }, // 顯示軸線
  axisTick: { show: true }, // 顯示刻度
  axisLabel: {
    color: '#333',
    fontSize: 12
  } // 刻度標籤樣式
},

050.png

坐標軸的 type 是一個關鍵屬性,它決定了坐標軸如何解析數據:

  • 'value': 數值軸。適用於連續數據,會自動根據 series.data 的最大最小值來生成刻度。
  • 'category': 類目軸。適用於離散的類目數據,類目數據需要通過 xAxis.data 來指定。
  • 'time': 時間軸。適用於連續的時序數據,能自動格式化時間標籤。
  • 'log': 對數軸。適用於數據跨度非常大的情況。

yAxis 的配置與 xAxis 類似。在一個圖表中,可以有多個 X 軸和 Y 軸,通過 xAxisIndexyAxisIndex 來關聯 series

grid:繪圖網格

grid 組件定義了直角坐標系在圖表容器中的位置和大小。當你想調整圖表主體部分(不包括標題、圖例等)的時候,就需要配置它。

grid: {
  left: '3%', // 網格區域離容器左側的距離
  right: '4%',
  bottom: '3%',
  top: '10%',
  containLabel: true // 防止標籤溢出
},

containLabel: true 是一個非常實用的配置,它會自動計算坐標軸標籤的寬度,並調整 grid 的位置,以確保標籤能夠完整顯示。

title:標題

一個圖表應該有一個明確的標題。title 組件用於配置主標題和副標題。

title: {
  text: '網站月度訪問量', // 主標題
  subtext: '數據來源:模擬數據', // 副標題
  left: 'center', // 標題水平居中
  textStyle: {
    color: '#c23531',
    fontSize: 20
  }
},

tooltip:提示框

當鼠標懸浮到圖表的數據項上時,tooltip 組件可以顯示詳細的數據信息,這是圖表交互的重要一環。

tooltip: {
  trigger: 'axis', // 觸發類型
  axisPointer: { // 坐標軸指示器配置
    type: 'shadow' // 默認為直線,可選為:'line' | 'shadow' | 'cross'
  }
},

trigger 屬性決定了提示框的觸發方式:

  • 'item': 數據項觸發。鼠標懸浮到單個數據項(如柱狀圖的某個柱子、餅圖的某個扇區)時觸發。
  • 'axis': 坐標軸觸發。鼠標懸浮到坐標軸的某個刻度上時,會同時顯示該刻度下所有系列的數據。常用於折線圖和柱狀圖。
  • 'none': 不觸發。

你可以通過 formatter 函數來自定義提示框顯示的內容,支持 HTML 字串和回調函數,給予了極高的靈活度。

legend:圖例

當圖表包含多個系列時,legend (圖例) 組件用於區分不同的系列。

legend: {
  data: ['銷量', '產量'], // 圖例項的名稱,需要與 series 的 name 對應
  top: 'bottom' // 圖例位置
},

legendseries 是通過 name 屬性關聯的。點擊圖例項,能控制對應系列的顯示和隱藏,這是 ECharts 內置的交互行為。

dataset:數據集

從 ECharts 4 開始,引入了 dataset 組件,這是一個非常重要的概念,它實現了數據與配置的分離

在之前的例子中,我們的數據是直接寫在 series.data 裡的。當數據量較大,或者多個系列需要共用同一份數據時,這種方式就顯得很臃腫。

dataset 允許我們統一定義數據源,然後在 series 中通過 encode 來映射數據。

var option = {
  dataset: {
    // 提供一份數據。
    source: [
      ["product", "2015", "2016", "2017"],
      ["Matcha Latte", 43.3, 85.8, 93.7],
      ["Milk Tea", 83.1, 73.4, 55.1],
      ["Cheese Cocoa", 86.4, 65.2, 82.5],
      ["Walnut Brownie", 72.4, 53.9, 39.1],
    ],
  },
  // 聲明一個 X 軸,類目軸(category)。默認情況下,類目軸對應到 dataset 第一列。
  xAxis: { type: "category" },
  // 聲明一個 Y 軸,數值軸。
  yAxis: {},
  // 聲明多個 series。
  series: [{ type: "bar" }, { type: "bar" }, { type: "bar" }],
};

在這個例子中,dataset.source 定義了一個二維數組。ECharts 會默認將第一行/第一列作為維度(dimension)。series 中甚至不需要寫 data,ECharts 會自動從 dataset 中取數據。第一列 product 映射到 xAxis,後續的 '2015', '2016', '2017' 三列數據,依次映射到三個 series

使用 dataset 的好處是:

  1. 數據復用:一份數據可以被多個系列、多個組件(如 visualMap)使用。
  2. 數據轉換:可以配合 data-transform 對數據進行篩選、聚合等預處理。
  3. 代碼清晰:將數據邏輯和樣式配置分離開,更易於維護。

強烈推薦在開發中優先使用 dataset 來管理數據。

實戰:高三年級期末考試多維分析

理論知識總是枯燥的,讓我們通過一個綜合案例,將前面學到的知識點串聯起來。

背景:假設我們是某高中的數據分析師,拿到了一份高三年級本次期末考試的成績單。我們需要通過數據可視化的方式,從多個維度對這次考試進行分析,為教學工作提供數據支持。

數據維度:班級、學生姓名、各科成績(語文、數學、英語、物理、化學、生物)、總分。

場景一:各班級平均總分對比(柱狀圖)

分析目標:直觀對比各個班級的平均總分,了解班級間的整體學習水平差異。

045.png

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>場景一:各班級平均總分對比</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
  </head>
  <body>
    <div id="bar-chart" style="width: 100%; height: 500px;"></div>
    <script type="text/javascript">
      // --- 數據準備 ---
      function generateMockData() {
        const classes = [
          "高三(1)班",
          "高三(2)班",
          "高三(3)班",
          "高三(4)班",
          "高三(5)班",
          "高三(6)班",
        ];
        const subjects = ["語文", "數學", "英語", "物理", "化學", "生物"];
        const studentsPerClass = 50;
        let data = [];
        let studentId = 1;

        classes.forEach((className) => {
          for (let i = 0; i < studentsPerClass; i++) {
            let student = { 班級: className, 姓名: `學生${studentId}` };
            let totalScore = 0;
            subjects.forEach((subject) => {
              const score = Math.floor(Math.random() * 101) + 50;
              student[subject] = score;
              totalScore += score;
            });
            student["總分"] = totalScore;
            data.push(student);
            studentId++;
          }
        });
        return data;
      }

      const examData = generateMockData();

      function calculateClassAverage(data) {
        const classScores = {};
        data.forEach((student) => {
          const className = student["班級"];
          if (!classScores[className]) {
            classScores[className] = { total: 0, count: 0 };
          }
          classScores[className].total += student["總分"];
          classScores[className].count++;
        });

        const averageData = Object.keys(classScores).map((className) => ({
          className: className,
          averageScore: (
            classScores[className].total / classScores[className].count
          ).toFixed(2),
        }));
        averageData.sort((a, b) => b.averageScore - a.averageScore);
        return averageData;
      }

      const classAverageData = calculateClassAverage(examData);

      // --- ECharts 配置 ---
      var barChart = echarts.init(document.getElementById("bar-chart"));
      var barChartOption = {
        title: {
          text: "高三各班級期末考試平均總分對比",
          left: "center",
        },
        tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
        grid: { left: "3%", right: "4%", bottom: "3%", containLabel: true },
        xAxis: {
          type: "category",
          data: classAverageData.map((item) => item.className),
          axisLabel: { interval: 0, rotate: 30 },
        },
        yAxis: { type: "value", name: "平均分" },
        series: [
          {
            name: "平均總分",
            type: "bar",
            barWidth: "60%",
            data: classAverageData.map((item) => item.averageScore),
            itemStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: "#83bff6" },
                { offset: 0.5, color: "#188df0" },
                { offset: 1, color: "#188df0" },
              ]),
            },
            emphasis: {
              itemStyle: {
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                  { offset: 0, color: "#2378f7" },
                  { offset: 0.7, color: "#2378f7" },
                  { offset: 1, color: "#83bff6" },
                ]),
              },
            },
            label: { show: true, position: "top" },
          },
        ],
      };
      barChart.setOption(barChartOption);
    </script>
  </body>
</html>

透過這個柱狀圖,我們可以一目了然地看出哪個班級的平均成績最高,哪個最低。

場景二:單科成績分佈情況(餅圖 & 玫瑰圖)

分析目標:以高三(1)班為例,分析數學單科成績的分佈情況(如:優秀、良好、及格、不及格)。

046.png

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>場景二:單科成績分佈</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
  </head>
  <body>
    <div id="pie-chart" style="width: 100%; height: 500px;"></div>
    <script type="text/javascript">
      // --- 數據準備 (復用上面的 generateMockData) ---
      function generateMockData() {
        const classes = [
          "高三(1)班",
          "高三(2)班",
          "高三(3)班",
          "高三(4)班",
          "高三(5)班",
          "高三(6)班",
        ];
        const subjects = ["語文", "數學", "英語", "物理", "化學", "生物"];
        const studentsPerClass = 50;
        let data = [];
        let studentId = 1;

        classes.forEach((className) => {
          for (let i = 0; i < studentsPerClass; i++) {
            let student = { 班級: className, 姓名: `學生${studentId}` };
            let totalScore = 0;
            subjects.forEach((subject) => {
              const score = Math.floor(Math.random() * 101) + 50;
              student[subject] = score;
              totalScore += score;
            });
            student["總分"] = totalScore;
            data.push(student);
            studentId++;
          }
        });
        return data;
      }

      const examData = generateMockData();

      function analyzeSubjectDistribution(data, className, subject) {
        const classData = data.filter(
          (student) => student["班級"] === className
        );
        const distribution = {
          "優秀 (120+)": 0,
          "良好 (100-119)": 0,
          "及格 (90-99)": 0,
          "不及格 (<90)": 0,
        };
        classData.forEach((student) => {
          const score = student[subject];
          if (score >= 120) distribution["優秀 (120+)"]++;
          else if (score >= 100) distribution["良好 (100-119)"]++;
          else if (score >= 90) distribution["及格 (90-99)"]++;
          else distribution["不及格 (<90)"]++;
        });
        return Object.keys(distribution).map((level) => ({
          name: level,
          value: distribution[level],
        }));
      }

      const mathDistributionData = analyzeSubjectDistribution(
        examData,
        "高三(1)班",
        "數學"
      );

      // --- ECharts 配置 ---
      var pieChart = echarts.init(document.getElementById("pie-chart"));
      var pieChartOption = {
        title: {
          text: "高三(1)班數學成績分佈",
          subtext: "期末考試",
          left: "center",
        },
        tooltip: {
          trigger: "item",
          formatter: "{a} <br/>{b} : {c}人 ({d}%)",
        },
        legend: {
          orient: "vertical",
          left: "left",
          data: mathDistributionData.map((item) => item.name),
        },
        series: [
          {
            name: "成績分佈",
            type: "pie",
            radius: "50%",
            center: ["50%", "60%"],
            data: mathDistributionData,
            // 可選:將 type: 'pie' 改為南丁格爾玫瑰圖,視覺效果更強
            // roseType: 'area',
            emphasis: {
              itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: "rgba(0, 0, 0, 0.5)",
              },
            },
          },
        ],
      };
      pieChart.setOption(pieChartOption);
    </script>
  </body>
</html>

餅圖清晰地展示了各個分數段的人數占比。如果將 series.roseType 設置為 'area',它會變成一個南丁格爾玫瑰圖,扇區的半徑會根據數據大小進行調整,視覺衝擊力更強。

場景三:理科綜合成績關聯性分析(散點圖)

分析目標:探究學生的物理成績和化學成績之間是否存在關聯性。比如,是不是物理好的學生,化學也普遍不錯?

047.png

::: details 完整代碼

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>場景三:理科綜合成績關聯性分析</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
  </head>
  <body>
    <div id="scatter-chart" style="width: 100%; height: 500px;"></div>
    <script type="text/javascript">
      // --- 數據準備 (復用上面的 generateMockData) ---
      function generateMockData() {
        const classes = [
          "高三(1)班",
          "高三(2)班",
          "高三(3)班",
          "高三(4)班",
          "高三(5)班",
          "高三(6)班",
        ];
        const subjects = ["語文", "數學", "英語", "物理", "化學", "生物"];
        const studentsPerClass = 50;
        let data = [];
        let studentId = 1;

        classes.forEach((className) => {
          for (let i = 0; i < studentsPerClass; i++) {
            let student = { 班級: className, 姓名: `學生${studentId}` };
            let totalScore = 0;
            subjects.forEach((subject) => {
              const score = Math.floor(Math.random() * 101) + 50;
              student[subject] = score;
              totalScore += score;
            });
            student["總分"] = totalScore;
            data.push(student);
            studentId++;
          }
        });
        return data;
      }

      const examData = generateMockData();

      function getSubjectCorrelationData(data, subjectX, subjectY) {
        // 返回格式: [物理成績, 化學成績, 學生姓名, 班級]
        return data.map((student) => [
          student[subjectX],
          student[subjectY],
          student["姓名"],
          student["班級"],
        ]);
      }

      const correlationData = getSubjectCorrelationData(
        examData,
        "物理",
        "化學"
      );

      // --- ECharts 配置 ---
      var scatterChart = echarts.init(document.getElementById("scatter-chart"));
      var scatterChartOption = {
        title: {
          text: "高三年級物理-化學成績關聯性分析",
          left: "center",
        },
        grid: { left: "3%", right: "7%", bottom: "3%", containLabel: true },
        xAxis: {
          type: "value",
          name: "物理成績",
          splitLine: { lineStyle: { type: "dashed" } },
        },
        yAxis: {
          type: "value",
          name: "化學成績",
          splitLine: { lineStyle: { type: "dashed" } },
        },
        tooltip: {
          trigger: "item",
          formatter: function (params) {
            // params.data 是一個數組 [物理成績, 化學成績, 姓名, 班級]
            return `${params.data[3]} - ${params.data[2]}<br/>物理: ${params.data[0]}<br/>化學: ${params.data[1]}`;
          },
        },
        series: [
          {
            name: "學生",
            type: "scatter",
            symbolSize: 6,
            data: correlationData,
            itemStyle: { color: "rgba(25, 100, 150, 0.6)" },
          },
        ],
      };
      scatterChart.setOption(scatterChartOption);
    </script>
  </body>
</html>

:::

透過觀察散點圖的分佈趨勢,我們可以做出初步判斷。如果點主要集中在從左下到右上的對角線區域,則說明物理和化學成績呈正相關關係。我們還可以輕易地發現那些“偏科”的異常點(比如物理很高但化學很低的學生)。

場景四:尖子生各科能力模型(雷達圖)

分析目標:選取總分排名前三的學生,用雷達圖對比他們的各科能力,分析他們的學科優勢與短板。

048.png

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>場景四:尖子生各科能力模型</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
  </head>
  <body>
    <div id="radar-chart" style="width: 100%; height: 500px;"></div>
    <script type="text/javascript">
      // --- 數據準備 (復用上面的 generateMockData) ---
      function generateMockData() {
        const classes = [
          "高三(1)班",
          "高三(2)班",
          "高三(3)班",
          "高三(4)班",
          "高三(5)班",
          "高三(6)班",
        ];
        const subjects = ["語文", "數學", "英語", "物理", "化學", "生物"];
        const studentsPerClass = 50;
        let data = [];
        let studentId = 1;

        classes.forEach((className) => {
          for (let i = 0; i < studentsPerClass; i++) {
            let student = { 班級: className, 姓名: `學生${studentId}` };
            let totalScore = 0;
            subjects.forEach((subject) => {
              const score = Math.floor(Math.random() * 101) + 50;
              student[subject] = score;
              totalScore += score;
            });
            student["總分"] = totalScore;
            data.push(student);
            studentId++;
          }
        });
        return data;
      }

      const examData = generateMockData();

      function getTopStudents(data, topCount) {
        const sorted = data.sort((a, b) => b["總分"] - a["總分"]);
        return sorted.slice(0, topCount);
      }

      const topStudents = getTopStudents(examData, 3);
      const radarData = topStudents.map(student => ({
        name: student["姓名"],
        value: [
          student["語文"],
          student["數學"],
          student["英語"],
          student["物理"],
          student["化學"],
          student["生物"]
        ]
      }));

      // --- ECharts 配置 ---
      var radarChart = echarts.init(document.getElementById("radar-chart"));
      var radarChartOption = {
        title: {
          text: "尖子生各科能力模型",
          left: "center",
        },
        legend: {
          data: topStudents.map(student => student["姓名"]),
          bottom: "0%",
        },
        radar: {
          indicator: [
            { name: '語文', max: 100 },
            { name: '數學', max: 100 },
            { name: '英語', max: 100 },
            { name: '物理', max: 100 },
            { name: '化學', max: 100 },
            { name: '生物', max: 100 }
          ],
          shape: 'circle',
          splitNumber: 5,
          name: {
            textStyle: {
              color: '#999',
            },
          },
          splitLine: {
            lineStyle: {
              color: ['#999', '#999', '#999', '#999', '#999', '#999'],
            }
          },
          splitArea: {
            areaStyle: {
              color: ['rgba(255, 255, 255, 0.1)', 'rgba(255, 255, 255, 0.5)'],
            }
          }
        },
        series: [{
          type: 'radar',
          data: radarData,
          areaStyle: { normal: {} }
        }]
      };
      radarChart.setOption(radarChartOption);
    </script>
  </body>
</html>

這樣,我們就可以清晰地看到尖子生在各科的表現,幫助他們明確自身的強項與弱項,以便於未來的學習規劃。


原文出處:https://juejin.cn/post/7553834935381409792


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝12   💬9   ❤️4
557
🥈
我愛JS
📝3   💬9   ❤️7
190
🥉
AppleLily
📝1   💬4   ❤️1
68
#4
💬1  
3
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付