Vue3 + TypeScript + Vite + Echarts

Vue3 + TypeScript + Vite + Echarts

vue echarts
vue echarts
vue echarts
vue echarts

1、创建工程

npm create vite@latest
cd echarts
npm install
npm run dev

2、安装项目依赖模块

npm install @types/node --save-dev

npm install vue-router@4

npm install animate.css --save
npm install gsap --save

npm install fetch --save
npm install axios --save

npm install pinia

npm install less less-loader -D
npm install sass sass-loader --save-dev
npm install scss scss-loader --save-dev

npm install element-plus --save
npm install -D unplugin-vue-components unplugin-auto-import

npm install echarts echarts-wordcloud --save

3、配置vite

vite.config.ts

import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  server: {
    host: '0.0.0.0',
    port: 5173,
    strictPort: true,
    open:true,
    proxy: {
      // 使用 proxy 实例
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, 'api'),
      },
    }
  },
})

3.1 配置路径别名

vite.config.ts

import {resolve} from "node:path";

resolve: {
    alias: {
      '@': resolve(__dirname, 'src')
    },
    // 引入文件的时候,可以忽略掉以下文件后缀
    // extensions: ['.js', '.mjs', '.vue', '.json', '.less', '.css']
  },
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import {resolve} from "node:path";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  server: {
    host: '0.0.0.0',
    port: 5173,
    strictPort: true,
    open:true,
    proxy: {
      // 使用 proxy 实例
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, 'api'),
      },
    }
  },
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src')
    },
    // 引入文件的时候,可以忽略掉以下文件后缀
    // extensions: ['.js', '.mjs', '.vue', '.json', '.less', '.css']
  },
})

ts.config.node.json

/* 路径别名 */
"types": ["node"],
"baseUrl": ".",
"paths": {
  "@/*": ["src/*"]
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2023"],
    "module": "ESNext",
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,

    /* 路径别名 */
    "types": ["node"],
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": ["vite.config.ts"]
}

3.2 引入路由

3.2.1 创建路由出口视图并在 app.vue 组件中引入 路由出口视图

HelloEcharts

<script setup lang="ts">

</script>

<template>
  <router-view/>
</template>

<style scoped>

</style>

app.vue

<script setup lang="ts">
import HelloEcharts from "@/components/HelloEcharts.vue";
</script>

<template>
  <hello-echarts/>
</template>

<style scoped>
</style>

3.2.2 创建路由文件

router.ts

import {createWebHashHistory, createWebHistory, createMemoryHistory, createRouter} from 'vue-router'

const routes = []

const router = createRouter({
  // 4. 内部提供了 history 模式的实现。
  // memory 模式。createMemoryHistory
  // hash 模式。createWebHashHistory
  // html5 模式。createWebHistory
  history: createMemoryHistory(),
  routes,
})
export default router
3.2.3 引入路由配置文件

main.ts

import {createApp} from 'vue';
import './style.css';
import App from './App.vue';
import router from "./routers/router.ts";

const app = createApp(App);
app.use(router);
app.mount('#app');

3.3 引入 animate.css 动画库

main.ts

import 'animate.css'
import {createApp} from 'vue';
import './style.css';
import 'animate.css'
import App from './App.vue';
import router from "./routers/router.ts";

const app = createApp(App);
app.use(router);
app.mount('#app');

3.4 引入 pinia

3.4.1 编写状态管理文件strore.ts

store.ts

import {defineStore} from 'pinia'
import {computed, reactive, ref} from "vue";


export const useStore = defineStore('main', () => {
  // ref() 和 reactive() 就是 state 属性
  // computed() 就是 getters
  // function() 就是 actions

  return {}
});
3.4.2 引入 pinia

main.ts

import {createPinia} from "pinia";
// 需要注意的是从pinia中解构出来的createPinia是一个函数,挂载前需要先调用执行
// const pinia = createPinia()
// app.use(pinia)
app.use(createPinia())
import {createApp} from 'vue';
import './style.css';
import 'animate.css'
import App from './App.vue';
import router from "./routers/router.ts";
import {createPinia} from "pinia";
const app = createApp(App);
// 需要注意的是从pinia中解构出来的createPinia是一个函数,挂载前需要先调用执行
// const pinia = createPinia()
// app.use(pinia)
app.use(createPinia())
app.use(router);
app.mount('#app');

3.5 配置 scss

3.5.1 编写scss 变量存储文件 scss_var.scss
3.5.2 引入 scss 变量配置文件 scss_var.scss

vite.config.ts

css: {
    preprocessorOptions: {
      scss: {
        // additionalData: '@import "./src/styles/scss_var.scss";'
        additionalData: `@use "./src/styles/scss_var.scss" as *;`,
      }
    }
  }
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import {resolve} from "node:path";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  server: {
    host: '0.0.0.0',
    port: 5173,
    strictPort: true,
    open:true,
    proxy: {
      // 使用 proxy 实例
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, 'api'),
      },
    }
  },
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src')
    },
    // 引入文件的时候,可以忽略掉以下文件后缀
    // extensions: ['.js', '.mjs', '.vue', '.json', '.less', '.css']
  },
  css: {
    preprocessorOptions: {
      scss: {
        // additionalData: '@import "./src/styles/scss_var.scss";'
        additionalData: `@use "./src/styles/scss_var.scss" as *;`,
      }
    }
  }
})

3.6配置 element plus

完整引入

按需导入

自动导入(本配置使用自动加载)

vite.config.ts

import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import {resolve} from "node:path";

import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      // resolvers: [ElementPlusResolver({importStyle: "sass"})],
      resolvers: [ElementPlusResolver()],
    }),
  ],
  server: {
    host: '0.0.0.0',
    port: 5173,
    strictPort: true,
    open:true,
    proxy: {
      // 使用 proxy 实例
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, 'api'),
      },
    }
  },
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src')
    },
    // 引入文件的时候,可以忽略掉以下文件后缀
    // extensions: ['.js', '.mjs', '.vue', '.json', '.less', '.css']
  },
  css: {
    preprocessorOptions: {
      scss: {
        // additionalData: '@import "./src/styles/scss_var.scss";'
        additionalData: `@use "./src/styles/scss_var.scss" as *;`,
      }
    }
  }
})

4、echarts快速入门

echarts官网:https://echarts.apache.org/zh/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>echarts快速入门</title>
    <!-- 引入刚刚下载的 ECharts 文件 -->
    <script src="node_modules/echarts/dist/echarts.js"></script>
</head>
<body>
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div id="main" style="width: 1200px;height:800px;"></div>
<script>
  // 基于准备好的dom,初始化echarts实例
  let myChart = echarts.init(document.getElementById('main'));
  // 指定图表的配置项和数据
  let option = {
    // 标题
    title: {
      // 标题内容
      text: 'ECharts 入门示例'
    },
    tooltip: {},
    // 图例
    legend: {
      // 图例名称
      data: ['销量','销售额']
    },
    xAxis: {
      // 坐标轴类型 category 为维度轴
      type: 'category',
      data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
    },
    yAxis: {
      // value 值轴
      type: 'value',
    },
    // 值轴数据
    series: [
      {
        // 图例名称
        name: '销量',
        // 图表样式 bar柱状图 line折线图
        type: 'bar',
        // 数值
        data: [5, 20, 36, 10, 10, 20]
      },
      {
        name: '销售额',
        type: 'line',
        data: [5, 20, 36, 10, 10, 20]
      }
    ]
  };
  // 使用刚指定的配置项和数据显示图表。
  myChart.setOption(option);
</script>
</body>
</html>

5、vue整合echarts

main.ts 中删除引入的样式 style.css

import {createApp} from 'vue';
// import './style.css';
import 'animate.css'
import App from './App.vue';
import router from "./routers/router.ts";
import {createPinia} from "pinia";
const app = createApp(App);
// 需要注意的是从pinia中解构出来的createPinia是一个函数,挂载前需要先调用执行
// const pinia = createPinia()
// app.use(pinia)
app.use(createPinia())
app.use(router);
app.mount('#app');

设置主页 htmlbody 标签的 内外边距为 0
index.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <link rel="icon" type="image/svg+xml" href="/vite.svg"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Vite + Vue + TS + Echarts</title>
    <style>
        html, body {
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

5.1 scss_var.scss文件中配置单个组件高度变量

// 单个图表 宽度和高度
$chart-width: 100%;
$chart-height: 100%;

5.2 ChartBar.vue

<script setup lang="ts">
import * as echarts  from 'echarts'
import {onMounted, ref, useTemplateRef} from "vue";
const chartBar = ref();
// const chartBar = useTemplateRef('chartBar');
function charBarInit() {
  // 基于准备好的dom,初始化echarts实例
  let barChart = echarts.init(chartBar.value,'dark');

// 指定图表的配置项和数据
  let option = {
    // 标题
    title: {
      // 标题内容
      text: 'ECharts 入门示例'
    },
    tooltip: {},
    // 图例
    legend: {
      // 图例名称
      data: ['销量','销售额']
    },
    xAxis: {
      // 坐标轴类型 category 为维度轴
      type: 'category',
      data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
    },
    yAxis: {
      // value 值轴
      type: 'value',
    },
    // 值轴数据
    series: [
      {
        // 图例名称
        name: '销量',
        // 图表样式 bar柱状图 line折线图
        type: 'bar',
        // 数值
        data: [5, 20, 36, 10, 10, 20]
      },
      {
        name: '销售额',
        type: 'line',
        data: [5, 20, 36, 10, 10, 20]
      }
    ]
  };
// 使用刚指定的配置项和数据显示图表。
  barChart.setOption(option);
  window.addEventListener('resize', () => {
    barChart.resize();
  })
}
onMounted(()=>{
  charBarInit();
});
</script>

<template>
<div id="chartBar" ref="chartBar"></div>
</template>

<style scoped lang="scss">
#chartBar{
  width: $chart-width;
  height: $chart-height;
}
</style><script setup lang="ts">
import * as echarts  from 'echarts'
import {onMounted, ref, useTemplateRef} from "vue";
const chartBar = ref();
// const chartBar = useTemplateRef('chartBar');
function charBarInit() {
  // 基于准备好的dom,初始化echarts实例
  let barChart = echarts.init(chartBar.value,'dark');

// 指定图表的配置项和数据
  let option = {
    // 标题
    title: {
      // 标题内容
      text: 'ECharts 入门示例'
    },
    tooltip: {},
    // 图例
    legend: {
      // 图例名称
      data: ['销量','销售额']
    },
    xAxis: {
      // 坐标轴类型 category 为维度轴
      type: 'category',
      data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
    },
    yAxis: {
      // value 值轴
      type: 'value',
    },
    // 值轴数据
    series: [
      {
        // 图例名称
        name: '销量',
        // 图表样式 bar柱状图 line折线图
        type: 'bar',
        // 数值
        data: [5, 20, 36, 10, 10, 20]
      },
      {
        name: '销售额',
        type: 'line',
        data: [5, 20, 36, 10, 10, 20]
      }
    ]
  };
// 使用刚指定的配置项和数据显示图表。
  barChart.setOption(option);
  window.addEventListener('resize', () => {
    barChart.resize();
  })
}
onMounted(()=>{
  charBarInit();
});
</script>

<template>
<div id="chartBar" ref="chartBar"></div>
</template>

<style scoped lang="scss">
#chartBar{
  width: $chart-width;
  height: $chart-height;
}
</style>

5.3 ChartBarView.vue

引入 ChartBar 组件

<script setup lang="ts">
import ChartBar from "@/views/ChartBar.vue";
</script>

<template>
  <div style="width: 100vw; height: 100vh"><chart-bar/></div>
</template>

<style scoped>

</style>

5.4 配置路由

router.ts

import {createWebHashHistory, createWebHistory, createMemoryHistory, createRouter} from 'vue-router'
import ChartBarView from "../views/ChartBarView.vue";
const routes = [
  {
    path: '/ChartBarView',
    name: 'ChartBarView',
    component: ChartBarView
  }
]

const router = createRouter({
  // 4. 内部提供了 history 模式的实现。
  // memory 模式。createMemoryHistory
  // hash 模式。createWebHashHistory
  // html5 模式。createWebHistory
  history: createWebHistory(),
  routes,
})
export default router

5.5 主体布局

HelloEcharts.vue

<script setup lang="ts">
</script>

<template>
  <!-- 页面容器 -->
  <div class="container">
    <!-- 头部标题 -->
    <div class="header">echarts可视化图表示例</div>
    <!-- 页面主体 -->
    <div class="main">
      <!-- 左侧导航菜单 -->
      <div class="nav">
      </div>
      <!-- 右侧图表显示区域 -->
      <div class="char-content">
        <!-- 路由出口 -->
        <router-view/>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
$background-color-header: #2f363c;
$background-color-nav: #545c64;
$background-color-main: #545c64;
.container {
  display: flex;
  flex-direction: column;

  .header {
    display: flex;
    justify-content: center;
    width: 100vw;
    height: 60px;
    line-height: 60px;
    font-size: 36px;
    background-color: $background-color-header;
    color: #f9f9f9;
  }

  .main {
    width: 100vw;
    height: calc(100vh - 60px);
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: stretch;
    background-color: $background-color-main;

    .nav {
      background-color: $background-color-nav;
      min-width: 65px;
      width: 150px;
    }

    .char-content {
      flex: 1;
    }
  }
}
</style>

5.6 左侧导航

NavView.vue

<script setup lang="ts">
import {computed, reactive, ref} from 'vue'
import {useRouter} from "vue-router";

import {
  Document,
  Menu as IconMenu,
  Location,
  Setting,
  Expand,
  Fold
} from '@element-plus/icons-vue'

const isCollapse = ref(false);
// 路由对象
const router = useRouter()

const router_list = reactive([
  {name: 'index'},
  {name: 'ChartBarView'},
  {name: 'ChartLineView'},
  {name: 'ChartPieView'},
]);

const count = ref(0);
const index = ref(1);
const index_string = computed(() => {
  return index.value.toString();
});
const to = (obj) => {
  router.push({
    name: obj.name,
  });
  for (let i = 0; i < router_list.length; i++) {
    if (router_list[i].name === obj.name) {
      count.value = i;
      index.value = i + 1;
      break;
    }
  }
}
// setInterval(() => {
//   to(router_list[count.value]);
//   count.value++;
//   index.value = count.value + 1;
//   if (count.value === routers.length) {
//     count.value = 0;
//     index.value = 1;
//   }
// }, 1000 * 30);
</script>

<template>
  <div style="font-size: 40px;">
    <el-icon v-show="isCollapse" @click="isCollapse = !isCollapse">
      <Expand/>
    </el-icon>
    <el-icon v-show="!isCollapse" @click="isCollapse = !isCollapse">
      <Fold/>
    </el-icon>
  </div>
  <el-menu
      active-text-color="#ffd04b"
      background-color="#545c64"
      text-color="#fff"
      class="el-menu-vertical-demo"
      :collapse="isCollapse"
      :default-active="index_string">
    <el-menu-item index="1" @click="to(router_list[0])">
      <el-icon>
        <icon-menu/>
      </el-icon>
      <template #title>首&nbsp;&nbsp;&nbsp;&nbsp;页</template>
    </el-menu-item>
    <el-menu-item index="2" @click="to(router_list[1])">
      <el-icon>
        <icon-menu/>
      </el-icon>
      <template #title>柱状图</template>
    </el-menu-item>
    <el-menu-item index="3" @click="to(router_list[2])">
      <el-icon>
        <icon-menu/>
      </el-icon>
      <template #title>折线图</template>
    </el-menu-item>
    <el-menu-item index="4" @click="to(router_list[3])">
      <el-icon>
        <icon-menu/>
      </el-icon>
      <template #title>饼&nbsp;&nbsp;&nbsp;&nbsp;图</template>
    </el-menu-item>
  </el-menu>
</template>

<style scoped>

</style>

HelloEcharts.vue中引入NavView.vue

<script setup lang="ts">
import NavView from "@/views/NavView.vue";
</script>

<template>
  <!-- 页面容器 -->
  <div class="container">
    <!-- 头部标题 -->
    <div class="header">echarts可视化图表示例</div>
    <!-- 页面主体 -->
    <div class="main">
      <!-- 左侧导航菜单 -->
      <div class="nav">
        <nav-view/>
      </div>
      <!-- 右侧图表显示区域 -->
      <div class="char-content">
        <!-- 路由出口 -->
        <router-view/>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
$background-color-header: #2f363c;
$background-color-nav: #545c64;
$background-color-main: #545c64;
.container {
  display: flex;
  flex-direction: column;

  .header {
    display: flex;
    justify-content: center;
    width: 100vw;
    height: 60px;
    line-height: 60px;
    font-size: 36px;
    background-color: $background-color-header;
    color: #f9f9f9;
  }

  .main {
    width: 100vw;
    height: calc(100vh - 60px);
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: stretch;
    background-color: $background-color-main;

    .nav {
      background-color: $background-color-nav;
      min-width: 65px;
      width: 150px;
    }

    .char-content {
      flex: 1;
    }
  }
}
</style>

5.7 封装Echarts公共组件

ChartLhz.vue

<script setup lang="ts">
import * as echarts from 'echarts'
import 'echarts-wordcloud'
import {onMounted, ref, defineProps, useTemplateRef} from "vue";
import {reactive} from "vue";

const chartBar = ref();

// const chartBar = useTemplateRef('chartBar');
// 接受父组件传递的图表的配置项和数据
const props = defineProps(['chart_option']);
const {chart_option} = props;
// 指定图表的配置项和数据
const option = reactive({});

function charBarInit() {
  // 基于准备好的dom,初始化echarts实例
  let barChart = echarts.init(chartBar.value, 'dark');
  // 指定图表的配置项和数据
  for (const filed in chart_option) {
    // 将父组件中传递过来的对象属性赋值给本地的对象
    option[filed] = chart_option[filed];
  }
  // 使用刚指定的配置项和数据显示图表。
  barChart.setOption(option);
  window.addEventListener('resize', () => {
    barChart.resize();
  })
}

onMounted(() => {
  charBarInit();
});
</script>

<template>
  <div id="chartBar" ref="chartBar"></div>
</template>

<style scoped lang="scss">
#chartBar {
  width: $chart-width;
  height: $chart-height;
}
</style>

5.8 编写图表全局样式

scss_var.scss

// 单个图表 宽度和高度
$chart-width: 100%;
$chart-height: 100%;

// 图表实例布局样式
.chart-container {
  width: 100%;
  display: flex;
  flex-direction: row;

  .chart-item {
    flex: 1;
    height: 490px;
    padding: 10px;
  }
}

5.9 柱状图

vue echarts

ChartBarView.vue

5.9.1 基础柱状图
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  // 标题
  title: {
    // 标题内容
    text: 'ECharts 入门示例'
  },
  tooltip: {},
  // 图例
  legend: {
    // 图例名称
    data: ['销量']
  },
  xAxis: {
    // 坐标轴类型 category 为维度轴
    type: 'category',
    data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
  },
  yAxis: {
    // value 值轴
    type: 'value',
  },
  // 值轴数据
  series: [
    {
      // 图例名称
      name: '销量',
      // 图表样式 bar柱状图 line折线图
      type: 'bar',
      // 数值
      data: [5, 20, 36, 10, 10, 20]
    },
  ]
});
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>
5.9.2 配置项
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  // 标题
  title: {
    // 标题内容
    text: 'ECharts 入门示例'
  },
  tooltip: {},
  // 图例
  legend: {
    // 图例名称
    data: ['销量']
  },
  xAxis: {
    // 坐标轴类型 category 为维度轴
    type: 'category',
    data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
  },
  yAxis: {
    // value 值轴
    type: 'value',
  },
  // 值轴数据
  series: [
    {
      // 图例名称
      name: '销量',
      // 图表样式 bar柱状图 line折线图
      type: 'bar',
      // 数值
      data: [5, 20, 36, 10, 10, 20]
    },
  ]
});
const option02 = reactive({
  // 标题
  title: {
    // 标题内容
    text: '每周花销',
    // 主标题链接
    link: 'https://space.bilibili.com/480308139',
    textStyle: {
      // 主标题文字的颜色。
      color: '#FF6060'
    },
    // 副标题文本
    subtext: '管我怎么花',
    // 主标题链接
    sublink: 'https://blog.csdn.net/qq_24330181',
  },
  tooltip: {
    formatter: '{b}:{a} >>> {c}'
  },
  // 图例
  legend: {
    // 图例名称
    data: ['早饭', '午饭', '晚饭']
  },
  toolbox: {
    // 各工具配置项
    feature: {
      // 保存图片
      saveAsImage: {
        type: 'png',
      },
      // 数据视图
      dataView: {
        show: true,
      },
      // 配置项还原
      restore: {},
      // 数据缩放
      dataZoom: {},
      // 图表样式切换
      magicType: {
        type: ['line', 'bar', 'stack'],
      }
    }
  },
  xAxis: {
    // 坐标轴类型。 category 类目轴
    type: 'category',
    // 数据
    data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'],
  },
  yAxis: {
    // value 值轴
    type: 'value',
  },
  // 值轴数据
  series: [
    {
      // 图例名称
      name: '早饭',
      // 图表样式 bar柱状图 line折线图
      type: 'bar',
      // 是否平滑 对 折线图有效
      smooth: true,
      // 数值
      data: [15, 15, 22, 21, 13, 14, 26],
      markPoint: {
        data: [
          {
            name: '本周早饭花销最多的一天',
            type: 'max',
          },
          {
            name: '本周早饭花销最少的一天',
            type: 'min',
          }
        ]
      },
      markLine: {
        data: [
          {
            name: '本周平均早饭花销',
            type: 'average',
          }
        ]
      }
    },
    {
      name: '午饭',
      type: 'bar',
      // 是否平滑 对 折线图有效
      smooth: true,
      data: [25, 28, 27, 26, 33, 24, 31],
      markPoint: {
        data: [
          {
            name: '本周午饭花销最多的一天',
            type: 'max',
          },
          {
            name: '本周午饭花销最少的一天',
            type: 'min',
          }
        ]
      },
      markLine: {
        data: [
          {
            name: '本周平均午饭花销',
            type: 'average',
          }
        ]
      }
    },
    {
      name: '晚饭',
      type: 'bar',
      // 是否平滑 对 折线图有效
      smooth: true,
      data: [35, 38, 27, 35, 35, 14, 29],
      markPoint: {
        data: [
          {
            name: '本周晚饭花销最多的一天',
            type: 'max',
          },
          {
            name: '本周晚饭花销最少的一天',
            type: 'min',
          }
        ]
      },
      markLine: {
        data: [
          {
            name: '本周平均晚饭花销',
            type: 'average',
          }
        ]
      }
    }
  ]
});
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option02"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>
5.9.3 值轴转换
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  // 标题
  title: {
    // 标题内容
    text: 'ECharts 入门示例'
  },
  tooltip: {},
  // 图例
  legend: {
    // 图例名称
    data: ['销量']
  },
  xAxis: {
    // 坐标轴类型 category 为维度轴
    type: 'category',
    data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
  },
  yAxis: {
    // value 值轴
    type: 'value',
  },
  // 值轴数据
  series: [
    {
      // 图例名称
      name: '销量',
      // 图表样式 bar柱状图 line折线图
      type: 'bar',
      // 数值
      data: [5, 20, 36, 10, 10, 20]
    },
  ]
});
const option02 = reactive({
  // 标题
  title: {
    // 标题内容
    text: '每周花销',
    // 主标题链接
    link: 'https://space.bilibili.com/480308139',
    textStyle: {
      // 主标题文字的颜色。
      color: '#FF6060'
    },
    // 副标题文本
    subtext: '管我怎么花',
    // 主标题链接
    sublink: 'https://blog.csdn.net/qq_24330181',
  },
  tooltip: {
    formatter: '{b}:{a} >>> {c}'
  },
  // 图例
  legend: {
    // 图例名称
    data: ['早饭', '午饭', '晚饭']
  },
  toolbox: {
    // 各工具配置项
    feature: {
      // 保存图片
      saveAsImage: {
        type: 'png',
      },
      // 数据视图
      dataView: {
        show: true,
      },
      // 配置项还原
      restore: {},
      // 数据缩放
      dataZoom: {},
      // 图表样式切换
      magicType: {
        type: ['line', 'bar', 'stack'],
      }
    }
  },
  xAxis: {
    // 坐标轴类型。 category 类目轴
    type: 'category',
    // 数据
    data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'],
  },
  yAxis: {
    // value 值轴
    type: 'value',
  },
  // 值轴数据
  series: [
    {
      // 图例名称
      name: '早饭',
      // 图表样式 bar柱状图 line折线图
      type: 'bar',
      // 是否平滑 对 折线图有效
      smooth: true,
      // 数值
      data: [15, 15, 22, 21, 13, 14, 26],
      markPoint: {
        data: [
          {
            name: '本周早饭花销最多的一天',
            type: 'max',
          },
          {
            name: '本周早饭花销最少的一天',
            type: 'min',
          }
        ]
      },
      markLine: {
        data: [
          {
            name: '本周平均早饭花销',
            type: 'average',
          }
        ]
      }
    },
    {
      name: '午饭',
      type: 'bar',
      // 是否平滑 对 折线图有效
      smooth: true,
      data: [25, 28, 27, 26, 33, 24, 31],
      markPoint: {
        data: [
          {
            name: '本周午饭花销最多的一天',
            type: 'max',
          },
          {
            name: '本周午饭花销最少的一天',
            type: 'min',
          }
        ]
      },
      markLine: {
        data: [
          {
            name: '本周平均午饭花销',
            type: 'average',
          }
        ]
      }
    },
    {
      name: '晚饭',
      type: 'bar',
      // 是否平滑 对 折线图有效
      smooth: true,
      data: [35, 38, 27, 35, 35, 14, 29],
      markPoint: {
        data: [
          {
            name: '本周晚饭花销最多的一天',
            type: 'max',
          },
          {
            name: '本周晚饭花销最少的一天',
            type: 'min',
          }
        ]
      },
      markLine: {
        data: [
          {
            name: '本周平均晚饭花销',
            type: 'average',
          }
        ]
      }
    }
  ]
});
const option03 = reactive({
  // 标题
  title: {
    // 标题内容
    text: '世界人口总量'
  },
  // 图例
  legend: {
    // 图例名称
    data: ['2011', '2012']
  },
  xAxis: {
    // value 值轴
    type: 'value',
  },
  yAxis: {

    // 坐标轴类型 category 为维度轴
    type: 'category',
    data: ['Brazil', 'Indonesia', 'USA', 'India', 'China', 'World']
  },
  // 值轴数据
  series: [
    {
      name: '2011',
      type: 'bar',
      data: [18203, 23489, 29034, 104970, 131744, 630230]
    },
    {
      name: '2012',
      type: 'bar',
      data: [19325, 23438, 31000, 121594, 134141, 681807]
    }
  ]
});
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option02"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option03"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>
5.9.4 正负条形图
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  // 标题
  title: {
    // 标题内容
    text: 'ECharts 入门示例'
  },
  tooltip: {},
  // 图例
  legend: {
    // 图例名称
    data: ['销量']
  },
  xAxis: {
    // 坐标轴类型 category 为维度轴
    type: 'category',
    data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
  },
  yAxis: {
    // value 值轴
    type: 'value',
  },
  // 值轴数据
  series: [
    {
      // 图例名称
      name: '销量',
      // 图表样式 bar柱状图 line折线图
      type: 'bar',
      // 数值
      data: [5, 20, 36, 10, 10, 20]
    },
  ]
});
const option02 = reactive({
  // 标题
  title: {
    // 标题内容
    text: '每周花销',
    // 主标题链接
    link: 'https://space.bilibili.com/480308139',
    textStyle: {
      // 主标题文字的颜色。
      color: '#FF6060'
    },
    // 副标题文本
    subtext: '管我怎么花',
    // 主标题链接
    sublink: 'https://blog.csdn.net/qq_24330181',
  },
  tooltip: {
    formatter: '{b}:{a} >>> {c}'
  },
  // 图例
  legend: {
    // 图例名称
    data: ['早饭', '午饭', '晚饭']
  },
  toolbox: {
    // 各工具配置项
    feature: {
      // 保存图片
      saveAsImage: {
        type: 'png',
      },
      // 数据视图
      dataView: {
        show: true,
      },
      // 配置项还原
      restore: {},
      // 数据缩放
      dataZoom: {},
      // 图表样式切换
      magicType: {
        type: ['line', 'bar', 'stack'],
      }
    }
  },
  xAxis: {
    // 坐标轴类型。 category 类目轴
    type: 'category',
    // 数据
    data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'],
  },
  yAxis: {
    // value 值轴
    type: 'value',
  },
  // 值轴数据
  series: [
    {
      // 图例名称
      name: '早饭',
      // 图表样式 bar柱状图 line折线图
      type: 'bar',
      // 是否平滑 对 折线图有效
      smooth: true,
      // 数值
      data: [15, 15, 22, 21, 13, 14, 26],
      markPoint: {
        data: [
          {
            name: '本周早饭花销最多的一天',
            type: 'max',
          },
          {
            name: '本周早饭花销最少的一天',
            type: 'min',
          }
        ]
      },
      markLine: {
        data: [
          {
            name: '本周平均早饭花销',
            type: 'average',
          }
        ]
      }
    },
    {
      name: '午饭',
      type: 'bar',
      // 是否平滑 对 折线图有效
      smooth: true,
      data: [25, 28, 27, 26, 33, 24, 31],
      markPoint: {
        data: [
          {
            name: '本周午饭花销最多的一天',
            type: 'max',
          },
          {
            name: '本周午饭花销最少的一天',
            type: 'min',
          }
        ]
      },
      markLine: {
        data: [
          {
            name: '本周平均午饭花销',
            type: 'average',
          }
        ]
      }
    },
    {
      name: '晚饭',
      type: 'bar',
      // 是否平滑 对 折线图有效
      smooth: true,
      data: [35, 38, 27, 35, 35, 14, 29],
      markPoint: {
        data: [
          {
            name: '本周晚饭花销最多的一天',
            type: 'max',
          },
          {
            name: '本周晚饭花销最少的一天',
            type: 'min',
          }
        ]
      },
      markLine: {
        data: [
          {
            name: '本周平均晚饭花销',
            type: 'average',
          }
        ]
      }
    }
  ]
});
const option03 = reactive({
  // 标题
  title: {
    // 标题内容
    text: '世界人口总量'
  },
  // 图例
  legend: {
    // 图例名称
    data: ['2011', '2012']
  },
  xAxis: {
    // value 值轴
    type: 'value',
  },
  yAxis: {

    // 坐标轴类型 category 为维度轴
    type: 'category',
    data: ['Brazil', 'Indonesia', 'USA', 'India', 'China', 'World']
  },
  // 值轴数据
  series: [
    {
      name: '2011',
      type: 'bar',
      data: [18203, 23489, 29034, 104970, 131744, 630230]
    },
    {
      name: '2012',
      type: 'bar',
      data: [19325, 23438, 31000, 121594, 134141, 681807]
    }
  ]
});
const option04 = reactive({
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'shadow'
    }
  },
  legend: {
    data: ['利润', '费用', '收入']
  },
  grid: {
    left: '3%',
    right: '4%',
    bottom: '3%',
    containLabel: true
  },
  xAxis: [
    {
      type: 'value'
    }
  ],
  yAxis: [
    {
      type: 'category',
      axisTick: {
        show: false
      },
      data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
    }
  ],
  series: [
    {
      name: '利润',
      type: 'bar',
      label: {
        show: true,
        position: 'inside'
      },
      emphasis: {
        focus: 'series'
      },
      data: [200, 170, 240, 244, 200, 220, 210]
    },
    {
      name: '收入',
      type: 'bar',
      stack: 'Total',
      label: {
        show: true
      },
      emphasis: {
        focus: 'series'
      },
      data: [320, 302, 341, 374, 390, 450, 420]
    },
    {
      name: '费用',
      type: 'bar',
      stack: 'Total',
      label: {
        show: true,
        position: 'left'
      },
      emphasis: {
        focus: 'series'
      },
      data: [-120, -132, -101, -134, -190, -230, -210]
    }
  ]
});
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option02"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option03"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option04"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>

5.10 折线图

vue echarts

ChartLineView.vue

配置路由

import {createWebHashHistory, createWebHistory, createMemoryHistory, createRouter} from 'vue-router'
import ChartBarView from "../views/ChartBarView.vue";
import ChartLineView from "../views/ChartLineView.vue";
const routes = [
  {
    path: '/ChartBarView',
    name: 'ChartBarView',
    component: ChartBarView
  },
  {
    path: '/ChartLineView',
    name: 'ChartLineView',
    component: ChartLineView
  }
]

const router = createRouter({
  // 4. 内部提供了 history 模式的实现。
  // memory 模式。createMemoryHistory
  // hash 模式。createWebHashHistory
  // html5 模式。createWebHistory
  history: createWebHistory(),
  routes,
})
export default router
5.10.1 基础折线图
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  xAxis: {
    type: 'category',
    data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [820, 932, 901, 934, 1290, 1330, 1320],
      type: 'line',
      smooth: true,
      itemStyle: {
        color: '#16b777'
      }
    }
  ]
});
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>
5.10.2 配置项
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  xAxis: {
    type: 'category',
    data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [820, 932, 901, 934, 1290, 1330, 1320],
      type: 'line',
      smooth: true,
      itemStyle: {
        color: '#16b777'
      }
    }
  ]
});
const option02 = reactive({
  title: {
    text: '一周温度变化'
  },
  tooltip: {
    trigger: 'axis'
  },
  legend: {},
  toolbox: {
    show: true,
    feature: {
      dataZoom: {
        yAxisIndex: 'none'
      },
      dataView: {readOnly: false},
      magicType: {type: ['line', 'bar']},
      restore: {},
      saveAsImage: {}
    }
  },
  xAxis: {
    type: 'category',
    boundaryGap: false,
    data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
  },
  yAxis: {
    type: 'value',
    axisLabel: {
      formatter: '{value} °C'
    }
  },
  series: [
    {
      name: '最高温度',
      type: 'line',
      data: [10, 11, 13, 11, 12, 12, 9],
      markPoint: {
        data: [
          {type: 'max', name: '最高点'},
          {type: 'min', name: '最低点'}
        ]
      },
      markLine: {
        data: [{type: 'average', name: '周平均最高温度'}]
      }
    },
    {
      name: '最低温度',
      type: 'line',
      data: [1, -2, 2, 5, 3, 2, 0],
      markPoint: {
        data: [{name: '周最低', value: -2, xAxis: 1, yAxis: -1.5}]
      },
      markLine: {
        data: [
          {type: 'average', name: '周平均最低温度'},
          [
            {
              symbol: 'none',
              x: '90%',
              yAxis: 'max'
            },
            {
              symbol: 'circle',
              label: {
                position: 'start',
                formatter: '最高点'
              },
              type: 'max',
              name: '最高点'
            }
          ]
        ]
      }
    }
  ]
});
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option02"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>
5.10.3 多坐标轴
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  xAxis: {
    type: 'category',
    data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [820, 932, 901, 934, 1290, 1330, 1320],
      type: 'line',
      smooth: true,
      itemStyle: {
        color: '#16b777'
      }
    }
  ]
});
const option02 = reactive({
  title: {
    text: '一周温度变化'
  },
  tooltip: {
    trigger: 'axis'
  },
  legend: {},
  toolbox: {
    show: true,
    feature: {
      dataZoom: {
        yAxisIndex: 'none'
      },
      dataView: {readOnly: false},
      magicType: {type: ['line', 'bar']},
      restore: {},
      saveAsImage: {}
    }
  },
  xAxis: {
    type: 'category',
    boundaryGap: false,
    data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
  },
  yAxis: {
    type: 'value',
    axisLabel: {
      formatter: '{value} °C'
    }
  },
  series: [
    {
      name: '最高温度',
      type: 'line',
      data: [10, 11, 13, 11, 12, 12, 9],
      markPoint: {
        data: [
          {type: 'max', name: '最高点'},
          {type: 'min', name: '最低点'}
        ]
      },
      markLine: {
        data: [{type: 'average', name: '周平均最高温度'}]
      }
    },
    {
      name: '最低温度',
      type: 'line',
      data: [1, -2, 2, 5, 3, 2, 0],
      markPoint: {
        data: [{name: '周最低', value: -2, xAxis: 1, yAxis: -1.5}]
      },
      markLine: {
        data: [
          {type: 'average', name: '周平均最低温度'},
          [
            {
              symbol: 'none',
              x: '90%',
              yAxis: 'max'
            },
            {
              symbol: 'circle',
              label: {
                position: 'start',
                formatter: '最高点'
              },
              type: 'max',
              name: '最高点'
            }
          ]
        ]
      }
    }
  ]
});

import {timeData, evaporation, rainfall} from "@/stores/line_option03.js"
let newData: string[] = timeData.map(item => item.replace('2009/', ''));
const option03 = reactive({
  title: {
    text: '蒸发量与降雨量关系',
    left: 'center'
  },
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      animation: false
    }
  },
  legend: {
    data: ['蒸发量', '降雨量'],
    left: 10
  },
  toolbox: {
    feature: {
      dataZoom: {
        yAxisIndex: 'none'
      },
      restore: {},
      saveAsImage: {}
    }
  },
  axisPointer: {
    link: [
      {
        xAxisIndex: 'all'
      }
    ]
  },
  dataZoom: [
    {
      show: true,
      realtime: true,
      start: 30,
      end: 70,
      xAxisIndex: [0, 1]
    },
    {
      type: 'inside',
      realtime: true,
      start: 30,
      end: 70,
      xAxisIndex: [0, 1]
    }
  ],
  grid: [
    {
      left: 60,
      right: 50,
      height: '30%'
    },
    {
      left: 60,
      right: 50,
      top: '55%',
      height: '30%'
    }
  ],
  xAxis: [
    {
      type: 'category',
      boundaryGap: false,
      axisLine: {onZero: true},
      data: newData
    },
    {
      gridIndex: 1,
      type: 'category',
      boundaryGap: false,
      axisLine: {onZero: true},
      data: newData,
      position: 'top'
    }
  ],
  yAxis: [
    {
      name: '蒸发量(m³/s)',
      type: 'value',
      max: 500
    },
    {
      gridIndex: 1,
      name: '降雨量(mm)',
      type: 'value',
      inverse: true
    }
  ],
  series: [
    {
      name: '蒸发量',
      type: 'line',
      symbolSize: 8,
      // prettier-ignore
      data: evaporation
    },
    {
      name: '降雨量',
      type: 'line',
      xAxisIndex: 1,
      yAxisIndex: 1,
      symbolSize: 8,
      // prettier-ignore
      data: rainfall
    }
  ]
});
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option02"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option03"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>
5.10.4 多坐标轴
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  xAxis: {
    type: 'category',
    data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [820, 932, 901, 934, 1290, 1330, 1320],
      type: 'line',
      smooth: true,
      itemStyle: {
        color: '#16b777'
      }
    }
  ]
});
const option02 = reactive({
  title: {
    text: '一周温度变化'
  },
  tooltip: {
    trigger: 'axis'
  },
  legend: {},
  toolbox: {
    show: true,
    feature: {
      dataZoom: {
        yAxisIndex: 'none'
      },
      dataView: {readOnly: false},
      magicType: {type: ['line', 'bar']},
      restore: {},
      saveAsImage: {}
    }
  },
  xAxis: {
    type: 'category',
    boundaryGap: false,
    data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
  },
  yAxis: {
    type: 'value',
    axisLabel: {
      formatter: '{value} °C'
    }
  },
  series: [
    {
      name: '最高温度',
      type: 'line',
      data: [10, 11, 13, 11, 12, 12, 9],
      markPoint: {
        data: [
          {type: 'max', name: '最高点'},
          {type: 'min', name: '最低点'}
        ]
      },
      markLine: {
        data: [{type: 'average', name: '周平均最高温度'}]
      }
    },
    {
      name: '最低温度',
      type: 'line',
      data: [1, -2, 2, 5, 3, 2, 0],
      markPoint: {
        data: [{name: '周最低', value: -2, xAxis: 1, yAxis: -1.5}]
      },
      markLine: {
        data: [
          {type: 'average', name: '周平均最低温度'},
          [
            {
              symbol: 'none',
              x: '90%',
              yAxis: 'max'
            },
            {
              symbol: 'circle',
              label: {
                position: 'start',
                formatter: '最高点'
              },
              type: 'max',
              name: '最高点'
            }
          ]
        ]
      }
    }
  ]
});

import {timeData, evaporation, rainfall} from "@/stores/line_option03.js"
let newData: string[] = timeData.map(item => item.replace('2009/', ''));
const option03 = reactive({
  title: {
    text: '蒸发量与降雨量关系',
    left: 'center'
  },
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      animation: false
    }
  },
  legend: {
    data: ['蒸发量', '降雨量'],
    left: 10
  },
  toolbox: {
    feature: {
      dataZoom: {
        yAxisIndex: 'none'
      },
      restore: {},
      saveAsImage: {}
    }
  },
  axisPointer: {
    link: [
      {
        xAxisIndex: 'all'
      }
    ]
  },
  dataZoom: [
    {
      show: true,
      realtime: true,
      start: 30,
      end: 70,
      xAxisIndex: [0, 1]
    },
    {
      type: 'inside',
      realtime: true,
      start: 30,
      end: 70,
      xAxisIndex: [0, 1]
    }
  ],
  grid: [
    {
      left: 60,
      right: 50,
      height: '30%'
    },
    {
      left: 60,
      right: 50,
      top: '55%',
      height: '30%'
    }
  ],
  xAxis: [
    {
      type: 'category',
      boundaryGap: false,
      axisLine: {onZero: true},
      data: newData
    },
    {
      gridIndex: 1,
      type: 'category',
      boundaryGap: false,
      axisLine: {onZero: true},
      data: newData,
      position: 'top'
    }
  ],
  yAxis: [
    {
      name: '蒸发量(m³/s)',
      type: 'value',
      max: 500
    },
    {
      gridIndex: 1,
      name: '降雨量(mm)',
      type: 'value',
      inverse: true
    }
  ],
  series: [
    {
      name: '蒸发量',
      type: 'line',
      symbolSize: 8,
      // prettier-ignore
      data: evaporation
    },
    {
      name: '降雨量',
      type: 'line',
      xAxisIndex: 1,
      yAxisIndex: 1,
      symbolSize: 8,
      // prettier-ignore
      data: rainfall
    }
  ]
});

import {time_data, flow_data, rain_data} from "@/stores/line_option04.ts"
let new_data = time_data.map(item => item.replace('_', '\n'));
const option04 = reactive({
  title: {
    text: '降雨量与流量关系',
    left: 'center'
  },
  grid: {
    bottom: 80
  },
  toolbox: {
    feature: {
      dataZoom: {
        yAxisIndex: 'none'
      },
      restore: {},
      saveAsImage: {}
    }
  },
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'cross',
      animation: false,
      label: {
        backgroundColor: '#505765'
      }
    }
  },
  legend: {
    data: ['流量', '降雨量'],
    left: 10
  },
  dataZoom: [
    {
      show: true,
      realtime: true,
      start: 65,
      end: 85
    },
    {
      type: 'inside',
      realtime: true,
      start: 65,
      end: 85
    }
  ],
  xAxis: [
    {
      type: 'category',
      boundaryGap: false,
      axisLine: {onZero: false},
      // prettier-ignore
      data: new_data
    }
  ],
  yAxis: [
    {
      name: '流量(m³/s)',
      type: 'value'
    },
    {
      name: '降雨量(mm)',
      nameLocation: 'start',
      alignTicks: true,
      type: 'value',
      inverse: true
    }
  ],
  series: [
    {
      name: '流量',
      type: 'line',
      areaStyle: {},
      lineStyle: {
        width: 1
      },
      emphasis: {
        focus: 'series'
      },
      markArea: {
        silent: true,
        itemStyle: {
          opacity: 0.3
        },
        data: [
          [
            {
              xAxis: '2009/9/12\n7:00'
            },
            {
              xAxis: '2009/9/22\n7:00'
            }
          ]
        ]
      },
      // prettier-ignore
      data: flow_data
    },
    {
      name: '降雨量',
      type: 'line',
      yAxisIndex: 1,
      areaStyle: {},
      lineStyle: {
        width: 1
      },
      emphasis: {
        focus: 'series'
      },
      markArea: {
        silent: true,
        itemStyle: {
          opacity: 0.3
        },
        data: [
          [
            {
              xAxis: '2009/9/10\n7:00'
            },
            {
              xAxis: '2009/9/20\n7:00'
            }
          ]
        ]
      },
      // prettier-ignore
      data: rain_data
    }
  ]
});
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option02"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option03"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option04"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>

5.11 饼图

vue echarts

ChartPieView.vue

配置路由

import {createWebHashHistory, createWebHistory, createMemoryHistory, createRouter} from 'vue-router'
import ChartBarView from "../views/ChartBarView.vue";
import ChartLineView from "../views/ChartLineView.vue";
import ChartPieView from "../views/ChartPieView.vue";
const routes = [
  {
    path: '/ChartBarView',
    name: 'ChartBarView',
    component: ChartBarView
  },
  {
    path: '/ChartLineView',
    name: 'ChartLineView',
    component: ChartLineView
  },
  {
    path: '/ChartPieView',
    name: 'ChartPieView',
    component: ChartPieView
  }
]

const router = createRouter({
  // 4. 内部提供了 history 模式的实现。
  // memory 模式。createMemoryHistory
  // hash 模式。createWebHashHistory
  // html5 模式。createWebHistory
  history: createWebHistory(),
  routes,
})
export default router
5.11.1 基础饼图
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  title: {
    text: '网站用户',
    subtext: '访问数据',
    left: 'center'
  },
  tooltip: {
    trigger: 'item'
  },
  legend: {
    // horizontal
    orient: 'vertical',
    left: 'left',
  },
  series: [
    {
      name: 'Access From',
      type: 'pie',
      radius: '50%',
      data: [
        {value: 1048, name: '搜索引擎'},
        {value: 735, name: '直接访问'},
        {value: 580, name: '推荐人'},
        {value: 484, name: '广告'},
        {value: 300, name: '视频'}
      ],
      emphasis: {
        itemStyle: {
          shadowBlur: 10,
          shadowOffsetX: 0,
          shadowColor: 'rgba(0, 0, 0, 0.5)'
        }
      }
    }
  ]
});
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>
5.11.2 环形图
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  title: {
    text: '网站用户',
    subtext: '访问数据',
    left: 'center'
  },
  tooltip: {
    trigger: 'item'
  },
  legend: {
    // horizontal
    orient: 'vertical',
    left: 'left',
  },
  series: [
    {
      name: 'Access From',
      type: 'pie',
      radius: '50%',
      data: [
        {value: 1048, name: '搜索引擎'},
        {value: 735, name: '直接访问'},
        {value: 580, name: '推荐人'},
        {value: 484, name: '广告'},
        {value: 300, name: '视频'}
      ],
      emphasis: {
        itemStyle: {
          shadowBlur: 10,
          shadowOffsetX: 0,
          shadowColor: 'rgba(0, 0, 0, 0.5)'
        }
      }
    }
  ]
});
const option02 = reactive({
  tooltip: {
    trigger: 'item'
  },
  legend: {
    top: '5%',
    left: 'center'
  },
  series: [
    {
      name: '访问来源',
      type: 'pie',
      // 第一个参数是内径 第二个参数是外径
      radius: ['40%', '70%'],
      avoidLabelOverlap: false,
      label: {
        show: false,
        position: 'center'
      },
      emphasis: {
        label: {
          show: true,
          fontSize: 40,
          fontWeight: 'bold'
        }
      },
      labelLine: {
        show: false
      },
      data: [
        {value: 1048, name: '搜索引擎'},
        {value: 735, name: '直接访问'},
        {value: 580, name: '推荐人'},
        {value: 484, name: '广告'},
        {value: 300, name: '视频'}
      ]
    }
  ]
});
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option02"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>
5.11.3 玫瑰图
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  title: {
    text: '网站用户',
    subtext: '访问数据',
    left: 'center'
  },
  tooltip: {
    trigger: 'item'
  },
  legend: {
    // horizontal
    orient: 'vertical',
    left: 'left',
  },
  series: [
    {
      name: 'Access From',
      type: 'pie',
      radius: '50%',
      data: [
        {value: 1048, name: '搜索引擎'},
        {value: 735, name: '直接访问'},
        {value: 580, name: '推荐人'},
        {value: 484, name: '广告'},
        {value: 300, name: '视频'}
      ],
      emphasis: {
        itemStyle: {
          shadowBlur: 10,
          shadowOffsetX: 0,
          shadowColor: 'rgba(0, 0, 0, 0.5)'
        }
      }
    }
  ]
});
const option02 = reactive({
  tooltip: {
    trigger: 'item'
  },
  legend: {
    top: '5%',
    left: 'center'
  },
  series: [
    {
      name: '访问来源',
      type: 'pie',
      // 第一个参数是内径 第二个参数是外径
      radius: ['40%', '70%'],
      avoidLabelOverlap: false,
      label: {
        show: false,
        position: 'center'
      },
      emphasis: {
        label: {
          show: true,
          fontSize: 40,
          fontWeight: 'bold'
        }
      },
      labelLine: {
        show: false
      },
      data: [
        {value: 1048, name: '搜索引擎'},
        {value: 735, name: '直接访问'},
        {value: 580, name: '推荐人'},
        {value: 484, name: '广告'},
        {value: 300, name: '视频'}
      ]
    }
  ]
});
const option03 = reactive({
  legend: {
    left: 'center',
    bottom: '30px',
  },
  toolbox: {
    show: true,
    feature: {
      mark: {show: true},
      dataView: {show: true, readOnly: false},
      restore: {show: true},
      saveAsImage: {show: true}
    }
  },
  series: [
    {
      name: '铿锵玫瑰',
      type: 'pie',
      radius: [50, 150],
      center: ['50%', '50%'],
      roseType: 'area',
      itemStyle: {
        borderRadius: 7
      },
      data: [
        {value: 40, name: 'rose 1'},
        {value: 38, name: 'rose 2'},
        {value: 32, name: 'rose 3'},
        {value: 30, name: 'rose 4'},
        {value: 28, name: 'rose 5'},
        {value: 26, name: 'rose 6'},
        {value: 22, name: 'rose 7'},
      ]
    }
  ]
});
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option02"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option03"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>
5.11.4 encode
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  title: {
    text: '网站用户',
    subtext: '访问数据',
    left: 'center'
  },
  tooltip: {
    trigger: 'item'
  },
  legend: {
    // horizontal
    orient: 'vertical',
    left: 'left',
  },
  series: [
    {
      name: 'Access From',
      type: 'pie',
      radius: '50%',
      data: [
        {value: 1048, name: '搜索引擎'},
        {value: 735, name: '直接访问'},
        {value: 580, name: '推荐人'},
        {value: 484, name: '广告'},
        {value: 300, name: '视频'}
      ],
      emphasis: {
        itemStyle: {
          shadowBlur: 10,
          shadowOffsetX: 0,
          shadowColor: 'rgba(0, 0, 0, 0.5)'
        }
      }
    }
  ]
});
const option02 = reactive({
  tooltip: {
    trigger: 'item'
  },
  legend: {
    top: '5%',
    left: 'center'
  },
  series: [
    {
      name: '访问来源',
      type: 'pie',
      // 第一个参数是内径 第二个参数是外径
      radius: ['40%', '70%'],
      avoidLabelOverlap: false,
      label: {
        show: false,
        position: 'center'
      },
      emphasis: {
        label: {
          show: true,
          fontSize: 40,
          fontWeight: 'bold'
        }
      },
      labelLine: {
        show: false
      },
      data: [
        {value: 1048, name: '搜索引擎'},
        {value: 735, name: '直接访问'},
        {value: 580, name: '推荐人'},
        {value: 484, name: '广告'},
        {value: 300, name: '视频'}
      ]
    }
  ]
});
const option03 = reactive({
  legend: {
    left: 'center',
    bottom: '30px',
  },
  toolbox: {
    show: true,
    feature: {
      mark: {show: true},
      dataView: {show: true, readOnly: false},
      restore: {show: true},
      saveAsImage: {show: true}
    }
  },
  series: [
    {
      name: '铿锵玫瑰',
      type: 'pie',
      radius: [50, 150],
      center: ['50%', '50%'],
      roseType: 'area',
      itemStyle: {
        borderRadius: 7
      },
      data: [
        {value: 40, name: 'rose 1'},
        {value: 38, name: 'rose 2'},
        {value: 32, name: 'rose 3'},
        {value: 30, name: 'rose 4'},
        {value: 28, name: 'rose 5'},
        {value: 26, name: 'rose 6'},
        {value: 22, name: 'rose 7'},
      ]
    }
  ]
});
const option04 = reactive({
  legend: {},
  tooltip: {},
  dataset: {
    source: [
      ['商品', '2012', '2013', '2014', '2015', '2016', '2017'],
      ['奶茶', 86.5, 92.1, 85.7, 83.1, 73.4, 55.1],
      ['格瓦斯', 41.1, 30.4, 65.1, 53.3, 83.8, 98.7],
      ['沈阳鸡架', 55.2, 67.1, 69.2, 72.4, 53.9, 39.1],
      ['哈尔滨红肠', 24.1, 67.2, 79.5, 86.4, 65.2, 82.5],
    ]
  },
  series: [
    {
      type: 'pie',
      radius: '20%',
      center: ['25%', '30%']
      // No encode specified, by default, it is '2012'.
    },
    {
      type: 'pie',
      radius: '20%',
      center: ['75%', '30%'],
      encode: {
        itemName: '商品',
        value: '2013'
      }
    },
    {
      type: 'pie',
      radius: '20%',
      center: ['25%', '75%'],
      encode: {
        itemName: '商品',
        value: '2014'
      }
    },
    {
      type: 'pie',
      radius: '20%',
      center: ['75%', '75%'],
      encode: {
        itemName: '商品',
        value: '2015'
      }
    }
  ]
});
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option02"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option03"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option04"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>
5.11.5 数据分割
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  title: {
    text: '网站用户',
    subtext: '访问数据',
    left: 'center'
  },
  tooltip: {
    trigger: 'item'
  },
  legend: {
    // horizontal
    orient: 'vertical',
    left: 'left',
  },
  series: [
    {
      name: 'Access From',
      type: 'pie',
      radius: '50%',
      data: [
        {value: 1048, name: '搜索引擎'},
        {value: 735, name: '直接访问'},
        {value: 580, name: '推荐人'},
        {value: 484, name: '广告'},
        {value: 300, name: '视频'}
      ],
      emphasis: {
        itemStyle: {
          shadowBlur: 10,
          shadowOffsetX: 0,
          shadowColor: 'rgba(0, 0, 0, 0.5)'
        }
      }
    }
  ]
});
const option02 = reactive({
  tooltip: {
    trigger: 'item'
  },
  legend: {
    top: '5%',
    left: 'center'
  },
  series: [
    {
      name: '访问来源',
      type: 'pie',
      // 第一个参数是内径 第二个参数是外径
      radius: ['40%', '70%'],
      avoidLabelOverlap: false,
      label: {
        show: false,
        position: 'center'
      },
      emphasis: {
        label: {
          show: true,
          fontSize: 40,
          fontWeight: 'bold'
        }
      },
      labelLine: {
        show: false
      },
      data: [
        {value: 1048, name: '搜索引擎'},
        {value: 735, name: '直接访问'},
        {value: 580, name: '推荐人'},
        {value: 484, name: '广告'},
        {value: 300, name: '视频'}
      ]
    }
  ]
});
const option03 = reactive({
  legend: {
    left: 'center',
    bottom: '30px',
  },
  toolbox: {
    show: true,
    feature: {
      mark: {show: true},
      dataView: {show: true, readOnly: false},
      restore: {show: true},
      saveAsImage: {show: true}
    }
  },
  series: [
    {
      name: '铿锵玫瑰',
      type: 'pie',
      radius: [50, 150],
      center: ['50%', '50%'],
      roseType: 'area',
      itemStyle: {
        borderRadius: 7
      },
      data: [
        {value: 40, name: 'rose 1'},
        {value: 38, name: 'rose 2'},
        {value: 32, name: 'rose 3'},
        {value: 30, name: 'rose 4'},
        {value: 28, name: 'rose 5'},
        {value: 26, name: 'rose 6'},
        {value: 22, name: 'rose 7'},
      ]
    }
  ]
});
const option04 = reactive({
  legend: {},
  tooltip: {},
  dataset: {
    source: [
      ['商品', '2012', '2013', '2014', '2015', '2016', '2017'],
      ['奶茶', 86.5, 92.1, 85.7, 83.1, 73.4, 55.1],
      ['格瓦斯', 41.1, 30.4, 65.1, 53.3, 83.8, 98.7],
      ['沈阳鸡架', 55.2, 67.1, 69.2, 72.4, 53.9, 39.1],
      ['哈尔滨红肠', 24.1, 67.2, 79.5, 86.4, 65.2, 82.5],
    ]
  },
  series: [
    {
      type: 'pie',
      radius: '20%',
      center: ['25%', '30%']
      // No encode specified, by default, it is '2012'.
    },
    {
      type: 'pie',
      radius: '20%',
      center: ['75%', '30%'],
      encode: {
        itemName: '商品',
        value: '2013'
      }
    },
    {
      type: 'pie',
      radius: '20%',
      center: ['25%', '75%'],
      encode: {
        itemName: '商品',
        value: '2014'
      }
    },
    {
      type: 'pie',
      radius: '20%',
      center: ['75%', '75%'],
      encode: {
        itemName: '商品',
        value: '2015'
      }
    }
  ]
});
const option05 = reactive({
  dataset: [
    {
      source: [
        ['Product', 'Sales', 'Price', 'Year'],
        ['Cake', 123, 32, 2011],
        ['Cereal', 231, 14, 2011],
        ['Tofu', 235, 5, 2011],
        ['Dumpling', 341, 25, 2011],
        ['Biscuit', 122, 29, 2011],
        ['Cake', 143, 30, 2012],
        ['Cereal', 201, 19, 2012],
        ['Tofu', 255, 7, 2012],
        ['Dumpling', 241, 27, 2012],
        ['Biscuit', 102, 34, 2012],
        ['Cake', 153, 28, 2013],
        ['Cereal', 181, 21, 2013],
        ['Tofu', 395, 4, 2013],
        ['Dumpling', 281, 31, 2013],
        ['Biscuit', 92, 39, 2013],
        ['Cake', 223, 29, 2014],
        ['Cereal', 211, 17, 2014],
        ['Tofu', 345, 3, 2014],
        ['Dumpling', 211, 35, 2014],
        ['Biscuit', 72, 24, 2014]
      ]
    },
    {
      transform: {
        type: 'filter',
        config: { dimension: 'Year', value: 2011 }
      }
    },
    {
      transform: {
        type: 'filter',
        config: { dimension: 'Year', value: 2012 }
      }
    },
    {
      transform: {
        type: 'filter',
        config: { dimension: 'Year', value: 2013 }
      }
    }
  ],
  series: [
    {
      type: 'pie',
      radius: 50,
      center: ['50%', '25%'],
      datasetIndex: 1
    },
    {
      type: 'pie',
      radius: 50,
      center: ['50%', '50%'],
      datasetIndex: 2
    },
    {
      type: 'pie',
      radius: 50,
      center: ['50%', '75%'],
      datasetIndex: 3
    }
  ],
});
let data_list = [
  [
    { name: '圣彼得堡来客', value: 5.6 },
    { name: '陀思妥耶夫斯基全集', value: 1 },
    { name: '史记精注全译(全6册)', value: 0.8 },
    { name: '加德纳艺术通史', value: 0.5 },
    { name: '表象与本质', value: 0.5 },
    { name: '其它', value: 3.8 }
  ],
  [
    { name: '银河帝国5:迈向基地', value: 3.8 },
    { name: '俞军产品方法论', value: 2.3 },
    { name: '艺术的逃难', value: 2.2 },
    { name: '第一次世界大战回忆录(全五卷)', value: 1.3 },
    { name: 'Scrum 精髓', value: 1.2 },
    { name: '其它', value: 5.7 }
  ],
  [
    { name: '克莱因壶', value: 3.5 },
    { name: '投资最重要的事', value: 2.8 },
    { name: '简读中国史', value: 1.7 },
    { name: '你当像鸟飞往你的山', value: 1.4 },
    { name: '表象与本质', value: 0.5 },
    { name: '其它', value: 3.8 }
  ]
];
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option02"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option03"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option04"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option05"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>
5.11.6 引导线调整
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

const option01 = reactive({
  title: {
    text: '网站用户',
    subtext: '访问数据',
    left: 'center'
  },
  tooltip: {
    trigger: 'item'
  },
  legend: {
    // horizontal
    orient: 'vertical',
    left: 'left',
  },
  series: [
    {
      name: 'Access From',
      type: 'pie',
      radius: '50%',
      data: [
        {value: 1048, name: '搜索引擎'},
        {value: 735, name: '直接访问'},
        {value: 580, name: '推荐人'},
        {value: 484, name: '广告'},
        {value: 300, name: '视频'}
      ],
      emphasis: {
        itemStyle: {
          shadowBlur: 10,
          shadowOffsetX: 0,
          shadowColor: 'rgba(0, 0, 0, 0.5)'
        }
      }
    }
  ]
});
const option02 = reactive({
  tooltip: {
    trigger: 'item'
  },
  legend: {
    top: '5%',
    left: 'center'
  },
  series: [
    {
      name: '访问来源',
      type: 'pie',
      // 第一个参数是内径 第二个参数是外径
      radius: ['40%', '70%'],
      avoidLabelOverlap: false,
      label: {
        show: false,
        position: 'center'
      },
      emphasis: {
        label: {
          show: true,
          fontSize: 40,
          fontWeight: 'bold'
        }
      },
      labelLine: {
        show: false
      },
      data: [
        {value: 1048, name: '搜索引擎'},
        {value: 735, name: '直接访问'},
        {value: 580, name: '推荐人'},
        {value: 484, name: '广告'},
        {value: 300, name: '视频'}
      ]
    }
  ]
});
const option03 = reactive({
  legend: {
    left: 'center',
    bottom: '30px',
  },
  toolbox: {
    show: true,
    feature: {
      mark: {show: true},
      dataView: {show: true, readOnly: false},
      restore: {show: true},
      saveAsImage: {show: true}
    }
  },
  series: [
    {
      name: '铿锵玫瑰',
      type: 'pie',
      radius: [50, 150],
      center: ['50%', '50%'],
      roseType: 'area',
      itemStyle: {
        borderRadius: 7
      },
      data: [
        {value: 40, name: 'rose 1'},
        {value: 38, name: 'rose 2'},
        {value: 32, name: 'rose 3'},
        {value: 30, name: 'rose 4'},
        {value: 28, name: 'rose 5'},
        {value: 26, name: 'rose 6'},
        {value: 22, name: 'rose 7'},
      ]
    }
  ]
});
const option04 = reactive({
  legend: {},
  tooltip: {},
  dataset: {
    source: [
      ['商品', '2012', '2013', '2014', '2015', '2016', '2017'],
      ['奶茶', 86.5, 92.1, 85.7, 83.1, 73.4, 55.1],
      ['格瓦斯', 41.1, 30.4, 65.1, 53.3, 83.8, 98.7],
      ['沈阳鸡架', 55.2, 67.1, 69.2, 72.4, 53.9, 39.1],
      ['哈尔滨红肠', 24.1, 67.2, 79.5, 86.4, 65.2, 82.5],
    ]
  },
  series: [
    {
      type: 'pie',
      radius: '20%',
      center: ['25%', '30%']
      // No encode specified, by default, it is '2012'.
    },
    {
      type: 'pie',
      radius: '20%',
      center: ['75%', '30%'],
      encode: {
        itemName: '商品',
        value: '2013'
      }
    },
    {
      type: 'pie',
      radius: '20%',
      center: ['25%', '75%'],
      encode: {
        itemName: '商品',
        value: '2014'
      }
    },
    {
      type: 'pie',
      radius: '20%',
      center: ['75%', '75%'],
      encode: {
        itemName: '商品',
        value: '2015'
      }
    }
  ]
});
const option05 = reactive({
  dataset: [
    {
      source: [
        ['Product', 'Sales', 'Price', 'Year'],
        ['Cake', 123, 32, 2011],
        ['Cereal', 231, 14, 2011],
        ['Tofu', 235, 5, 2011],
        ['Dumpling', 341, 25, 2011],
        ['Biscuit', 122, 29, 2011],
        ['Cake', 143, 30, 2012],
        ['Cereal', 201, 19, 2012],
        ['Tofu', 255, 7, 2012],
        ['Dumpling', 241, 27, 2012],
        ['Biscuit', 102, 34, 2012],
        ['Cake', 153, 28, 2013],
        ['Cereal', 181, 21, 2013],
        ['Tofu', 395, 4, 2013],
        ['Dumpling', 281, 31, 2013],
        ['Biscuit', 92, 39, 2013],
        ['Cake', 223, 29, 2014],
        ['Cereal', 211, 17, 2014],
        ['Tofu', 345, 3, 2014],
        ['Dumpling', 211, 35, 2014],
        ['Biscuit', 72, 24, 2014]
      ]
    },
    {
      transform: {
        type: 'filter',
        config: { dimension: 'Year', value: 2011 }
      }
    },
    {
      transform: {
        type: 'filter',
        config: { dimension: 'Year', value: 2012 }
      }
    },
    {
      transform: {
        type: 'filter',
        config: { dimension: 'Year', value: 2013 }
      }
    }
  ],
  series: [
    {
      type: 'pie',
      radius: 50,
      center: ['50%', '25%'],
      datasetIndex: 1
    },
    {
      type: 'pie',
      radius: 50,
      center: ['50%', '50%'],
      datasetIndex: 2
    },
    {
      type: 'pie',
      radius: 50,
      center: ['50%', '75%'],
      datasetIndex: 3
    }
  ],
});
let data_list = [
  [
    { name: '圣彼得堡来客', value: 5.6 },
    { name: '陀思妥耶夫斯基全集', value: 1 },
    { name: '史记精注全译(全6册)', value: 0.8 },
    { name: '加德纳艺术通史', value: 0.5 },
    { name: '表象与本质', value: 0.5 },
    { name: '其它', value: 3.8 }
  ],
  [
    { name: '银河帝国5:迈向基地', value: 3.8 },
    { name: '俞军产品方法论', value: 2.3 },
    { name: '艺术的逃难', value: 2.2 },
    { name: '第一次世界大战回忆录(全五卷)', value: 1.3 },
    { name: 'Scrum 精髓', value: 1.2 },
    { name: '其它', value: 5.7 }
  ],
  [
    { name: '克莱因壶', value: 3.5 },
    { name: '投资最重要的事', value: 2.8 },
    { name: '简读中国史', value: 1.7 },
    { name: '你当像鸟飞往你的山', value: 1.4 },
    { name: '表象与本质', value: 0.5 },
    { name: '其它', value: 3.8 }
  ]
];
const option06 = reactive({
  title: {
    text: '阅读书籍分布',
    left: 'center',
    textStyle: {
      color: '#999',
      fontWeight: 'normal',
      fontSize: 14
    }
  },
  series: data_list.map(function (data, idx) {
    let top = idx * 33.3;
    return {
      type: 'pie',
      radius: [20, 60],
      top: top + '%',
      height: '33.33%',
      left: 'center',
      width: '100%',
      itemStyle: {
        borderColor: '#fff',
        borderWidth: 1
      },
      label: {
        // 文字末端对齐
        alignTo: 'edge',
        formatter: '{name|{b}}\n{time|{c} 小时}',
        minMargin: 5,
        edgeDistance: 10,
        lineHeight: 15,
        rich: {
          time: {
            fontSize: 10,
            color: '#999'
          }
        }
      },
      labelLine: {
        length: 15,
        length2: 0,
        maxSurfaceAngle: 80
      },
      data: data
    };
  })
});
</script>

<template>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option01"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option02"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option03"/>
    </div>
  </div>
  <div class="chart-container">
    <div class="chart-item">
      <chart-lhz :chart_option="option04"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option05"/>
    </div>
    <div class="chart-item">
      <chart-lhz :chart_option="option06"/>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>

5.12 默认首页

vue echarts

该页面包含了 漏斗图 雷达图 仪表盘 词云 地图 散点图

5.12.1 页面布局

scss_var.scss

// 单个图表 宽度和高度
$chart-width: 100%;
$chart-height: 100%;

// 图表实例布局样式
.chart-container {
  width: 100%;
  display: flex;
  flex-direction: row;

  .side-item {
    width: 100%;
  }

  .chart-item {
    flex: 1;
    height: 490px;
    padding: 10px;
  }
}

IndexView.vue

<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import {reactive} from "vue";

</script>

<template>
  <div class="chart-container">
    <div class="side-item">
      <div class="chart-item">
        <chart-lhz />
      </div>
      <div class="chart-item">
        <chart-lhz />
      </div>
    </div>
    <div style="flex: 0 1 150%;">
      <div class="chart-item" style="height: 1000px;">
        <chart-lhz />
      </div>
    </div>
    <div class="side-item">
      <div class="chart-item">
        <chart-lhz />
      </div>
      <div class="chart-item">
        <chart-lhz />
      </div>
    </div>
  </div>

</template>

<style scoped lang="scss">
@import "@/styles/scss_var";
</style>

配置路由

import {createWebHashHistory, createWebHistory, createMemoryHistory, createRouter} from 'vue-router'
import ChartBarView from "../views/ChartBarView.vue";
import ChartLineView from "../views/ChartLineView.vue";
import ChartPieView from "../views/ChartPieView.vue";
import IndexView from "../views/IndexView.vue";

const routes = [
  {
    path: '/ChartBarView',
    name: 'ChartBarView',
    component: ChartBarView
  },
  {
    path: '/ChartLineView',
    name: 'ChartLineView',
    component: ChartLineView
  },
  {
    path: '/ChartPieView',
    name: 'ChartPieView',
    component: ChartPieView
  },
  {
    path: '/',
    name: 'IndexView',
    component: IndexView
  }
]

const router = createRouter({
  // 4. 内部提供了 history 模式的实现。
  // memory 模式。createMemoryHistory
  // hash 模式。createWebHashHistory
  // html5 模式。createWebHistory
  history: createWebHistory(),
  routes,
})
export default router
5.12.2 漏斗图
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import ChartMap from "@/views/ChartMap.vue";
import {reactive} from "vue";
// 漏斗图
const funnel_option = reactive({
  title: {
    text: '漏斗图',
    left: 'center',
  },
  tooltip: {
    trigger: 'item',
    formatter: '{a} <br/>{b} : {c}%'
  },
  legend: {
    data: ['Show', 'Click', 'Visit', 'Inquiry', 'Order'],
    bottom: '20px',
  },
  series: [
    {
      name: '漏斗图',
      type: 'funnel',
      left: '10%',
      top: 60,
      bottom: 60,
      width: '80%',
      min: 0,
      max: 100,
      minSize: '0%',
      maxSize: '100%',
      sort: 'descending',
      gap: 2,
      label: {
        show: true,
        position: 'inside'
      },
      labelLine: {
        length: 10,
        lineStyle: {
          width: 1,
          type: 'solid'
        }
      },
      itemStyle: {
        borderColor: '#fff',
        borderWidth: 1,
      },
      emphasis: {
        label: {
          fontSize: 20
        }
      },
      data: [
        {value: 75, name: 'Visit'},
        {value: 50, name: 'Inquiry'},
        {value: 35, name: 'Order'},
        {value: 95, name: 'Click'},
        {value: 100, name: 'Show'}
      ]
    }
  ]
});
// 雷达图
// 仪表盘
// 词云
</script>

<template>
  <div class="chart-container">
    <div class="side-item">
      <div class="chart-item">
        <chart-lhz :chart_option="funnel_option"/>
      </div>
      <div class="chart-item">
        <chart-lhz :chart_option="funnel_option"/>
      </div>
    </div>
    <div style="flex: 0 1 150%;">
      <div class="chart-item" style="height: 1000px;">
         <chart-lhz :chart_option="funnel_option"/>
      </div>
    </div>
    <div class="side-item">
      <div class="chart-item">
        <chart-lhz :chart_option="funnel_option"/>
      </div>
      <div class="chart-item">
        <chart-lhz :chart_option="funnel_option"/>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import '@/styles/scss_var';
</style>
5.12.3 雷达图
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import ChartMap from "@/views/ChartMap.vue";
import {reactive} from "vue";
// 漏斗图
const funnel_option = reactive({
  title: {
    text: '漏斗图',
    left: 'center',
  },
  tooltip: {
    trigger: 'item',
    formatter: '{a} <br/>{b} : {c}%'
  },
  legend: {
    data: ['Show', 'Click', 'Visit', 'Inquiry', 'Order'],
    bottom: '20px',
  },
  series: [
    {
      name: '漏斗图',
      type: 'funnel',
      left: '10%',
      top: 60,
      bottom: 60,
      width: '80%',
      min: 0,
      max: 100,
      minSize: '0%',
      maxSize: '100%',
      sort: 'descending',
      gap: 2,
      label: {
        show: true,
        position: 'inside'
      },
      labelLine: {
        length: 10,
        lineStyle: {
          width: 1,
          type: 'solid'
        }
      },
      itemStyle: {
        borderColor: '#fff',
        borderWidth: 1,
      },
      emphasis: {
        label: {
          fontSize: 20
        }
      },
      data: [
        {value: 75, name: 'Visit'},
        {value: 50, name: 'Inquiry'},
        {value: 35, name: 'Order'},
        {value: 95, name: 'Click'},
        {value: 100, name: 'Show'}
      ]
    }
  ]
});
// 雷达图
const radar_option = reactive({
  title: {
    text: '预算与支出'
  },
  legend: {
    data: ['预算费用', '实付费用']
  },
  radar: {
    // shape: 'circle',
    indicator: [
      {name: '差旅', max: 6500},
      {name: '服务器', max: 16000},
      {name: '网络设备', max: 30000},
      {name: '配电设置', max: 38000},
      {name: '空调', max: 52000},
      {name: '技术服务', max: 25000}
    ]
  },
  series: [
    {
      name: '预算与支出',
      type: 'radar',
      data: [
        {
          value: [4200, 3000, 20000, 35000, 50000, 18000],
          name: '预算费用'
        },
        {
          value: [5000, 14000, 28000, 26000, 42000, 21000],
          name: '实付费用'
        }
      ]
    }
  ]
});
// 仪表盘
// 词云
</script>

<template>
  <div class="chart-container">
    <div class="side-item">
      <div class="chart-item">
        <chart-lhz :chart_option="funnel_option"/>
      </div>
      <div class="chart-item">
        <chart-lhz :chart_option="radar_option"/>
      </div>
    </div>
    <div style="flex: 0 1 150%;">
      <div class="chart-item" style="height: 1000px;">
         <chart-lhz :chart_option="funnel_option"/>
      </div>
    </div>
    <div class="side-item">
      <div class="chart-item">
        <chart-lhz :chart_option="funnel_option"/>
      </div>
      <div class="chart-item">
        <chart-lhz :chart_option="funnel_option"/>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import '@/styles/scss_var';
</style>
5.12.4 仪表盘
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import ChartMap from "@/views/ChartMap.vue";
import {reactive} from "vue";
// 漏斗图
const funnel_option = reactive({
  title: {
    text: '漏斗图',
    left: 'center',
  },
  tooltip: {
    trigger: 'item',
    formatter: '{a} <br/>{b} : {c}%'
  },
  legend: {
    data: ['Show', 'Click', 'Visit', 'Inquiry', 'Order'],
    bottom: '20px',
  },
  series: [
    {
      name: '漏斗图',
      type: 'funnel',
      left: '10%',
      top: 60,
      bottom: 60,
      width: '80%',
      min: 0,
      max: 100,
      minSize: '0%',
      maxSize: '100%',
      sort: 'descending',
      gap: 2,
      label: {
        show: true,
        position: 'inside'
      },
      labelLine: {
        length: 10,
        lineStyle: {
          width: 1,
          type: 'solid'
        }
      },
      itemStyle: {
        borderColor: '#fff',
        borderWidth: 1,
      },
      emphasis: {
        label: {
          fontSize: 20
        }
      },
      data: [
        {value: 75, name: 'Visit'},
        {value: 50, name: 'Inquiry'},
        {value: 35, name: 'Order'},
        {value: 95, name: 'Click'},
        {value: 100, name: 'Show'}
      ]
    }
  ]
});
// 雷达图
const radar_option = reactive({
  title: {
    text: '预算与支出'
  },
  legend: {
    data: ['预算费用', '实付费用']
  },
  radar: {
    // shape: 'circle',
    indicator: [
      {name: '差旅', max: 6500},
      {name: '服务器', max: 16000},
      {name: '网络设备', max: 30000},
      {name: '配电设置', max: 38000},
      {name: '空调', max: 52000},
      {name: '技术服务', max: 25000}
    ]
  },
  series: [
    {
      name: '预算与支出',
      type: 'radar',
      data: [
        {
          value: [4200, 3000, 20000, 35000, 50000, 18000],
          name: '预算费用'
        },
        {
          value: [5000, 14000, 28000, 26000, 42000, 21000],
          name: '实付费用'
        }
      ]
    }
  ]
});
// 仪表盘
const gauge_option = reactive({
  series: [
    {
      type: 'gauge',
      axisLine: {
        lineStyle: {
          width: 30,
          color: [
            [0.25, '#16b777'],
            [0.4, '#31bdec'],
            [0.55, '#ffb800'],
            [1, '#fd666d']
          ]
        }
      },
      pointer: {
        itemStyle: {
          color: 'auto'
        }
      },
      axisTick: {
        distance: -30,
        length: 8,
        lineStyle: {
          color: '#fff',
          width: 2
        }
      },
      splitLine: {
        distance: -30,
        length: 30,
        lineStyle: {
          color: '#fff',
          width: 4
        }
      },
      axisLabel: {
        color: 'inherit',
        distance: 40,
        fontSize: 20
      },
      detail: {
        valueAnimation: true,
        formatter: '{value} 摄氏度',
        color: 'inherit'
      },
      data: [
        {
          value: 26
        }
      ]
    }
  ]
});
// 词云
</script>

<template>
  <div class="chart-container">
    <div class="side-item">
      <div class="chart-item">
        <chart-lhz :chart_option="funnel_option"/>
      </div>
      <div class="chart-item">
        <chart-lhz :chart_option="radar_option"/>
      </div>
    </div>
    <div style="flex: 0 1 150%;">
      <div class="chart-item" style="height: 1000px;">
         <chart-lhz :chart_option="funnel_option"/>
      </div>
    </div>
    <div class="side-item">
      <div class="chart-item">
        <chart-lhz :chart_option="gauge_option"/>
      </div>
      <div class="chart-item">
        <chart-lhz :chart_option="funnel_option"/>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import '@/styles/scss_var';
</style>
5.12.5 词云图

数据存储在 books.json 文件中

注意:词云模块需要单独安装和引入

<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import ChartMap from "@/views/ChartMap.vue";
import {reactive} from "vue";
// 漏斗图
const funnel_option = reactive({
  title: {
    text: '漏斗图',
    left: 'center',
  },
  tooltip: {
    trigger: 'item',
    formatter: '{a} <br/>{b} : {c}%'
  },
  legend: {
    data: ['Show', 'Click', 'Visit', 'Inquiry', 'Order'],
    bottom: '20px',
  },
  series: [
    {
      name: '漏斗图',
      type: 'funnel',
      left: '10%',
      top: 60,
      bottom: 60,
      width: '80%',
      min: 0,
      max: 100,
      minSize: '0%',
      maxSize: '100%',
      sort: 'descending',
      gap: 2,
      label: {
        show: true,
        position: 'inside'
      },
      labelLine: {
        length: 10,
        lineStyle: {
          width: 1,
          type: 'solid'
        }
      },
      itemStyle: {
        borderColor: '#fff',
        borderWidth: 1,
      },
      emphasis: {
        label: {
          fontSize: 20
        }
      },
      data: [
        {value: 75, name: 'Visit'},
        {value: 50, name: 'Inquiry'},
        {value: 35, name: 'Order'},
        {value: 95, name: 'Click'},
        {value: 100, name: 'Show'}
      ]
    }
  ]
});
// 雷达图
const radar_option = reactive({
  title: {
    text: '预算与支出'
  },
  legend: {
    data: ['预算费用', '实付费用']
  },
  radar: {
    // shape: 'circle',
    indicator: [
      {name: '差旅', max: 6500},
      {name: '服务器', max: 16000},
      {name: '网络设备', max: 30000},
      {name: '配电设置', max: 38000},
      {name: '空调', max: 52000},
      {name: '技术服务', max: 25000}
    ]
  },
  series: [
    {
      name: '预算与支出',
      type: 'radar',
      data: [
        {
          value: [4200, 3000, 20000, 35000, 50000, 18000],
          name: '预算费用'
        },
        {
          value: [5000, 14000, 28000, 26000, 42000, 21000],
          name: '实付费用'
        }
      ]
    }
  ]
});
// 仪表盘
const gauge_option = reactive({
  series: [
    {
      type: 'gauge',
      axisLine: {
        lineStyle: {
          width: 30,
          color: [
            [0.25, '#16b777'],
            [0.4, '#31bdec'],
            [0.55, '#ffb800'],
            [1, '#fd666d']
          ]
        }
      },
      pointer: {
        itemStyle: {
          color: 'auto'
        }
      },
      axisTick: {
        distance: -30,
        length: 8,
        lineStyle: {
          color: '#fff',
          width: 2
        }
      },
      splitLine: {
        distance: -30,
        length: 30,
        lineStyle: {
          color: '#fff',
          width: 4
        }
      },
      axisLabel: {
        color: 'inherit',
        distance: 40,
        fontSize: 20
      },
      detail: {
        valueAnimation: true,
        formatter: '{value} 摄氏度',
        color: 'inherit'
      },
      data: [
        {
          value: 26
        }
      ]
    }
  ]
});
// 词云
import book_list from '@/stores/books.json'
// 使用 map 提取 title,并使用 reduce 来统计次数
const titleCounts = book_list
    // 提取所有的 title
    .map(item => item.title)
    // acc累加器 item列表项
    // 第一个 {} 是函数体
    // 第二个 {} 是 reduce 方法中的初始值,如果没有初始值那么使用列表中的第一个元素作为初始值
    .reduce((acc, title) => {
      // 统计每个 title 的出现次数
      acc[title] = (acc[title] || 0) + 1;
      return acc;
    }, {});
// 将统计结果转换为所需的格式
const book_data = Object.entries(titleCounts).map(([name, value]) => ({
  name,   // title 名称
  value   // 出现次数
}))
const word_cloud_option = reactive({
  title: {text: '书名词云图'},
  series: [{
    type: 'wordCloud',
    data: book_data,
    textStyle: {
      color: function () {
        return 'rgb(' + [
          Math.round(Math.random() * 255),
          Math.round(Math.random() * 255),
          Math.round(Math.random() * 255)
        ].join(',') + ')';
      }
    }
  }]
});
</script>

<template>
  <div class="chart-container">
    <div class="side-item">
      <div class="chart-item">
        <chart-lhz :chart_option="funnel_option"/>
      </div>
      <div class="chart-item">
        <chart-lhz :chart_option="radar_option"/>
      </div>
    </div>
    <div style="flex: 0 1 150%;">
      <div class="chart-item" style="height: 1000px;">
         <chart-lhz :chart_option="funnel_option"/>
      </div>
    </div>
    <div class="side-item">
      <div class="chart-item">
        <chart-lhz :chart_option="gauge_option"/>
      </div>
      <div class="chart-item">
        <chart-lhz :chart_option="word_cloud_option"/>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import '@/styles/scss_var';
</style>
5.12.6 地图+散点图

省份数据保存在 china_province.json 文件中

中国地图经纬度坐标数据保存在 china_full.json 文件中

地区经纬度坐标:https://datav.aliyun.com/portal/school/atlas/area_selector

ChartMap.vue

<script setup lang="ts">
import * as echarts from 'echarts';
import china_geo from "@/stores/china_full.json"
import china_province from "@/stores/china_province.json"
import {onMounted, ref, reactive} from "vue";

const chartMap = ref()
// 数据转换
// 最终数据格式
// [{ name: '北京市', value: [116.405285, 39.904989, 90] }],
const convertData = function (data) {
  return data.map(province => {
    let obj =  china_geo.features.find(item => item.properties.name === province.name);
    let rs = {};
    rs.name = obj.properties.name;
    rs.value = [obj.properties.center[0], obj.properties.center[1], province.value];
    return rs;
  })
}
// 转换后的数据
const data = convertData(china_province);
function chartMapInit() {
  // 基于准备好的dom,初始化echarts实例
  const myChart = echarts.init(chartMap.value, 'dark');
  // 注入地图数据 GeoJson 注意第一个参数为 china 才会显示 海南岛缩略图 其它名字不会
  echarts.registerMap('china', china_geo);
  // 指定图表的配置项和数据
  const option = reactive({
    title: {
      text: '全国主要城市空气质量 - 百度地图',
      left: 'center'
    },
    tooltip: {
      trigger: 'item',
      formatter: function (params) {
        // console.log(params);
        return `${params.data.name}:${params.data.value[2]}`
      }
    },
    // 地图配置
    geo: {
      type: 'map',
      // chinaMap 这个参数 为 echarts.registerMap('chinaMap', response); 参数中第一个参数
      // 注意参数为 china 才会显示 海南岛缩略图 其它名字不会
      map: 'china',
      // 是否开启鼠标缩放和平移漫游。默认不开启。如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move'。设置成 true 为都开启
      roam: true,
      // 图形上的文本标签,可用于说明图形的一些数据信息,比如值,名称等
      label: {
        // 是否显示标签
        show: true
      },
      // 默认缩放比例
      zoom: 1.1,
      // 地图中心点坐标
      // 当前视角的中心点,默认使用原始坐标(经纬度)。如果设置了projection则用投影后的坐标表示。
      // center: [125.3245, 43.886841]
      itemStyle:{
        // areaColor: '#ff9090',
      }
    },
    series: [
      {
        geoIndex: 0,
        type: 'effectScatter',
        // 配置何时显示特效
        // 'render' 绘制完成后显示特效
        // 'emphasis' 高亮(hover)的时候显示特效。
        showEffectOn: 'render',
        // data: [{ name: '北京市', value: [116.405285, 39.904989, 9] }],
        data: convertData(china_province),
        // 使用地理坐标系,通过 geoIndex 指定相应的地理坐标系组件。
        coordinateSystem: 'geo',
        symbolSize: function (param) {
          // console.log(param[2]);
          return param[2] / 2
        },
      },

    ],
    // 是视觉映射组件,用于进行『视觉编码』,也就是将数据映射到视觉元素(视觉通道
    visualMap: {
      min: 0,
      max: 50,
      // 筛选
      calculable: true
    }
  });
  // 使用刚指定的配置项和数据显示图表。
  myChart.setOption(option);
  window.addEventListener('resize', function () {
    myChart.resize();
  });
}

onMounted(() => {
  chartMapInit();
});
</script>

<template>
  <div id="chartMap" ref="chartMap"></div>
</template>

<style scoped lang="scss">
#chartMap {
  width: $chart-width;
  height: $chart-height;
}
</style>
<script setup lang="ts">
import ChartLhz from "@/components/ChartLhz.vue";
import ChartMap from "@/views/ChartMap.vue";
import {reactive} from "vue";
// 漏斗图
const funnel_option = reactive({
  title: {
    text: '漏斗图',
    left: 'center',
  },
  tooltip: {
    trigger: 'item',
    formatter: '{a} <br/>{b} : {c}%'
  },
  legend: {
    data: ['Show', 'Click', 'Visit', 'Inquiry', 'Order'],
    bottom: '20px',
  },
  series: [
    {
      name: '漏斗图',
      type: 'funnel',
      left: '10%',
      top: 60,
      bottom: 60,
      width: '80%',
      min: 0,
      max: 100,
      minSize: '0%',
      maxSize: '100%',
      sort: 'descending',
      gap: 2,
      label: {
        show: true,
        position: 'inside'
      },
      labelLine: {
        length: 10,
        lineStyle: {
          width: 1,
          type: 'solid'
        }
      },
      itemStyle: {
        borderColor: '#fff',
        borderWidth: 1,
      },
      emphasis: {
        label: {
          fontSize: 20
        }
      },
      data: [
        {value: 75, name: 'Visit'},
        {value: 50, name: 'Inquiry'},
        {value: 35, name: 'Order'},
        {value: 95, name: 'Click'},
        {value: 100, name: 'Show'}
      ]
    }
  ]
});
// 雷达图
const radar_option = reactive({
  title: {
    text: '预算与支出'
  },
  legend: {
    data: ['预算费用', '实付费用']
  },
  radar: {
    // shape: 'circle',
    indicator: [
      {name: '差旅', max: 6500},
      {name: '服务器', max: 16000},
      {name: '网络设备', max: 30000},
      {name: '配电设置', max: 38000},
      {name: '空调', max: 52000},
      {name: '技术服务', max: 25000}
    ]
  },
  series: [
    {
      name: '预算与支出',
      type: 'radar',
      data: [
        {
          value: [4200, 3000, 20000, 35000, 50000, 18000],
          name: '预算费用'
        },
        {
          value: [5000, 14000, 28000, 26000, 42000, 21000],
          name: '实付费用'
        }
      ]
    }
  ]
});
// 仪表盘
const gauge_option = reactive({
  series: [
    {
      type: 'gauge',
      axisLine: {
        lineStyle: {
          width: 30,
          color: [
            [0.25, '#16b777'],
            [0.4, '#31bdec'],
            [0.55, '#ffb800'],
            [1, '#fd666d']
          ]
        }
      },
      pointer: {
        itemStyle: {
          color: 'auto'
        }
      },
      axisTick: {
        distance: -30,
        length: 8,
        lineStyle: {
          color: '#fff',
          width: 2
        }
      },
      splitLine: {
        distance: -30,
        length: 30,
        lineStyle: {
          color: '#fff',
          width: 4
        }
      },
      axisLabel: {
        color: 'inherit',
        distance: 40,
        fontSize: 20
      },
      detail: {
        valueAnimation: true,
        formatter: '{value} 摄氏度',
        color: 'inherit'
      },
      data: [
        {
          value: 26
        }
      ]
    }
  ]
});
// 词云
import book_list from '@/stores/books.json'
// 使用 map 提取 title,并使用 reduce 来统计次数
const titleCounts = book_list
    // 提取所有的 title
    .map(item => item.title)
    // acc累加器 item列表项
    // 第一个 {} 是函数体
    // 第二个 {} 是 reduce 方法中的初始值,如果没有初始值那么使用列表中的第一个元素作为初始值
    .reduce((acc, title) => {
      // 统计每个 title 的出现次数
      acc[title] = (acc[title] || 0) + 1;
      return acc;
    }, {});
// 将统计结果转换为所需的格式
const book_data = Object.entries(titleCounts).map(([name, value]) => ({
  name,   // title 名称
  value   // 出现次数
}))
const word_cloud_option = reactive({
  title: {text: '书名词云图'},
  series: [{
    type: 'wordCloud',
    data: book_data,
    textStyle: {
      color: function () {
        return 'rgb(' + [
          Math.round(Math.random() * 255),
          Math.round(Math.random() * 255),
          Math.round(Math.random() * 255)
        ].join(',') + ')';
      }
    }
  }]
});
</script>

<template>
  <div class="chart-container">
    <div class="side-item">
      <div class="chart-item">
        <chart-lhz :chart_option="funnel_option"/>
      </div>
      <div class="chart-item">
        <chart-lhz :chart_option="radar_option"/>
      </div>
    </div>
    <div style="flex: 0 1 150%;">
      <div class="chart-item" style="height: 1000px;">
        <chart-map/>
      </div>
    </div>
    <div class="side-item">
      <div class="chart-item">
        <chart-lhz :chart_option="gauge_option"/>
      </div>
      <div class="chart-item">
        <chart-lhz :chart_option="word_cloud_option"/>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
@import '@/styles/scss_var';
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/891656.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

跨境电商干货:Etsy选品及相关运营技巧分享

Etsy作为一个吸引了全球将近一亿消费者的电子商务平台&#xff0c;因其聚焦小众、原创、设计产品的特点而拥有相当不错的流量和潜力&#xff0c;如果需要优化自己的Etsy店铺选品工作&#xff0c;可以参考以下技巧。 一、选品方向 1.按需求 Etsy主张售卖富有创意的、由卖家制作…

三电平逆变器:技术原理与实际应用

三电平逆变器&#xff1a;技术原理与实际应用&#xff08;网盘https://pan.baidu.com/s/1KRV4DBMChwZiu5lKgo0bEA 提取码 8v8p&#xff09; 中点钳位三电平逆变器的特性 优点 1、在换流过程中&#xff0c;每个功率半导体器件所承受的电压均为Ud/2。这有助于逆变器电压等级和…

VScode中CMake无高亮(就是没有补全的提示)

在我学的过程中我发现我的CMake是这样的&#xff0c;如下图 但在教学视频里是这样的&#xff08;如下图&#xff09; 这非常的难受&#xff0c;所以疯狂的找&#xff0c;最后是CMake报错有 原因就是&#xff1a;本地没有配置环境变量&#xff0c;解决方法是下一个cmake然后直接…

【C】分支与循环2--while/for/do-while/goto以及break和continue在不同循环中的辨析~

分支与循环 while循环 if与while的对比 if(表达式)语句&#xff1b;while(表达式)语句&#xff1b;下面来看一个例子&#xff1a; 用 if 写&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main() {if (1)printf("hehe");//if后面条…

【千库网-注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

3、Docker搭建MQTT及Spring Boot 3.x集成MQTT

一、前言 本篇主要是围绕着两个点&#xff0c;1、Docker 搭建单机版本 MQTT&#xff08;EMQX&#xff09;&#xff0c;2、Spring Boot 3.x 集成 MQTT&#xff08;EMQX&#xff09;&#xff1b; 而且这里的 MQTT&#xff08;EMQX&#xff09;的搭建也只是一个简单的过程&#x…

uibot发送邮件:自动化邮件发送教程详解!

uibot发送邮件的操作指南&#xff1f;uibot发送邮件的两种方式&#xff1f; 在现代办公环境中&#xff0c;自动化流程的引入极大地提高了工作效率。uibot发送邮件功能成为了许多企业和个人实现邮件自动化发送的首选工具。AokSend将详细介绍如何使用uibot发送邮件。 uibot发送…

RHCE的学习(1)

一、 Linux的例行性工作 场景&#xff1a; 生活中&#xff0c;我们有太多场景需要使用到闹钟&#xff0c;比如早上 7 点起床&#xff0c;下午 4 点开会&#xff0c;晚上 8 点购物&#xff0c;等等。 在 Linux 系统里&#xff0c;我们同样也有类似的需求。比如我们想在凌晨 1 …

C++进阶:map和set的使用

目录 一.序列式容器和关联式容器 二.set系列的使用 2.1set容器的介绍 2.2set的构造和迭代器 2.3set的增删查 2.4insert和迭代器遍历的样例 2.5find和erase的样例 ​编辑 2.6multiset和set的差异 2.7简单用set解决两道题 两个数组的交集 环形链表二 三.map系列的使用…

Android Framework AMS(04)startActivity分析-1(am启动到ActivityThread启动)

该系列文章总纲链接&#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节主要解读AMS通过startActivity启动Activity的整个流程的第一阶段&#xff1a;从am启动到ActivityThread启动。 第二阶段文章链接为&#xf…

FFmpeg的简单使用【Windows】--- 视频倒叙播放

实现功能 点击【选择文件】按钮可以选择视频&#xff0c;当点击【开始处理】按钮之后&#xff0c;会先将视频上传到服务器&#xff0c;然后开始进行视频倒叙播放的处理&#xff0c;当视频处理完毕之后会将输出的文件路径返回&#xff0c;同时在页面中将处理好的视频展示出来。…

SHELL脚本之重定向符号的使用。

一.shell脚本&#xff08;对应完成某一个功能的命令熟悉与否&#xff0c;决定着shell脚本的熟练与否。&#xff09; 一个shell脚本就是一个普通的文本文件。 作用&#xff1a;将重复执行的操作写成脚本&#xff0c;自动执行。 二.Linux操作系统中重定向符号的使用。 类型&a…

ESP32接入扣子(Coze) API使用自定义智能体

使用ESP32接入Coze API实现聊天机器人的教程 本示例将使用ESP32开发板通过WiFi接入 Coze API&#xff0c;实现一个简单的聊天机器人功能。用户可以通过串口向机器人输入问题&#xff0c;ESP32将通过Coze API与智能体进行通信&#xff0c;并返回对应的回复。本文将详细介绍了如…

selenium有多个frame页时的操作方法(5)

之前文章我们提到&#xff0c;在webdriver.WebDriver类有一个switch_to方法&#xff0c;通过switch_to.frame()可以切换到不同的frame页然后才再定位某个元素做一些输入/点击等操作。 比如下面这个测试网站有2个frame页&#xff1a;http://www.sahitest.com/demo/framesTest.h…

wordpress 子比主题美化 四宫格 多宫格 布局插件

wordpress 主题美化 四宫格 多宫格 布局插件&#xff08;只在子比主题上测试过&#xff0c;其它主题没测试&#xff09; A5资源网四宫格布局插件是一个功能丰富的WordPress插件,专为创建自适应的四宫格布局而设计。这个插件具有以下主要特点: 灵活的布局: 支持1到8个宫格的自定…

如何设置 GitLab 密码长度?

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料&#xff1a; 极狐GitLab 60天专业…

星海智算:【RVC】无需部署一键启动

镜像介绍 RVC全称 Retrieval-based-Voice-Conversion-WebUI 简称 RVC 一个基于VITS的简单易用的语音转换&#xff08;变声器&#xff09;框架 RVC 是一款前沿的音色替换项目&#xff0c;可以进行歌曲的翻唱&#xff0c;和实时的变声&#xff0c;具有低延迟、优秀的变声效果、…

【可答疑】基于51单片机的自动烘手器(含仿真、代码、报告、演示视频等)

✨哈喽大家好&#xff0c;这里是每天一杯冰美式oh&#xff0c;985电子本硕&#xff0c;大厂嵌入式在职0.3年&#xff0c;业余时间做做单片机小项目&#xff0c;有需要也可以提供就业指导&#xff08;免费&#xff09;~ &#x1f431;‍&#x1f409;这是51单片机毕业设计100篇…

C++ 算法学习——1.8 快速幂算法

背景知识&#xff1a; 1.位运算 在C中&#xff0c;位运算是对整数类型的位进行操作的一种运算方式。常见的位运算符包括按位与&#xff08;&&#xff09;、按位或&#xff08;|&#xff09;、按位异或&#xff08;^&#xff09;、取反&#xff08;~&#xff09;、左移&am…

芯课堂 | Synwit_UI_Creator(μgui)平台之图像处理篇

今天小编给大家介绍的是UI_Creator&#xff08;μgui&#xff09;平台下关于图像处理的选项。 UI_Creator&#xff08;μgui&#xff09;平台图片类控件有图像控件和分级图像控件&#xff0c;均包含以下选项&#xff1a; 1、消除水波纹&#xff1a; 由于16位真彩色&#xff08…