Vue3 + TypeScript + Vite + Echarts

news2024/11/24 18:58:10

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>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024年源代码加密软件推荐,十款超好用的源代码加密软件推荐

在当今数字化时代&#xff0c;源代码的安全性对于企业和开发者来说至关重要。无论是为了保护知识产权&#xff0c;还是为了防止恶意攻击&#xff0c;选择一款可靠的源代码加密软件都是必不可少的。本文将为您推荐2024年十款超好用的源代码加密软件&#xff0c;帮助您在保护代码…

10款超好用的电脑加密软件推荐|2024年常用电脑加密软件排行榜

随着数字化办公的普及&#xff0c;企业的数据安全面临前所未有的挑战。文件的泄露、窃取和丢失不仅会影响企业的商业利益&#xff0c;还可能导致客户隐私泄露&#xff0c;进而影响企业声誉。因此&#xff0c;选择一款合适的加密软件来保护公司机密文件变得尤为重要。2024年&…

AI产品经理怎么准备面试啊?

最近有些小伙伴&#xff0c;想要求职AI领域的产品经理&#xff0c;特别是AIGC的产品经理&#xff0c;但是不知道面试官会问哪些问题&#xff0c;也就不知道如何开始准备&#xff1f;该准备哪些东西&#xff1f;要准备到什么程度&#xff1f;最终导致迟迟不敢开始。 下面总共5家…

多级代理与提权维权

目录 代理构建FRP介绍下载配置⽂件&#xff1a; sock5代理Venom介绍下载配置 icmpsh介绍下载配置 pingtunnel介绍下载配置 EarthWorm介绍下载使用 权限提升win权限提升常⻅利⽤⼯具 Linux权限提升SUID提权 权限维持win权限维持系统服务后⻔⾃启动⽬录注册表后⻔其他类似隐藏⽤户…

西安国际数字影像产业园:文化创意产业的加速器

西安国际数字影像产业园作为文化创意产业的加速器&#xff0c;正为西安乃至全国的文化创意产业发展注入强大动力&#xff1a; 优越的基础条件&#xff1a;西安作为历史文化名城&#xff0c;文化底蕴深厚&#xff0c;为数字影像产业提供了丰富的创作素材和灵感源泉。西安国际数…

magic-html : 通用HTML数据提取器!DocAI:从非结构化文档中提取结构化数据!强大、快速、开源的微信机器人底层框架:wcf.js!

magic-html : 通用HTML数据提取器&#xff01;DocAI&#xff1a;从非结构化文档中提取结构化数据&#xff01;强大、快速、开源的微信机器人底层框架&#xff1a;wcf.js&#xff01; magic-html : 通用HTML数据提取器 magic-html提供了一套工具&#xff0c;能够轻松地从HTML中…

闪电麦昆 语音控制齿轮行进轨迹,ESP32搭配语音控制板,串口通信,附视频演示地址

演示地址 https://www.bilibili.com/video/BV1cW421d79L/?vd_sourceb8515e53f6d4c564b541d98dcc9df990 语音控制板的配置 web展示页面 esp32 程序 #include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include <LittleFS.h> #include <WebSo…

最全方案解决Android Studio中使用lombok插件错误: 找不到符号的问题

直接原因 先直接说原因&#xff0c;小部分是因为配置错误导致的&#xff0c;注意查看下面的步骤即可&#xff0c;另一大部分是因为Java和Kotlin混编的问题&#xff0c;lombok和kapt冲突&#xff0c;其实你用了kotlin基本不需要用lombok&#xff0c;多此一举&#xff01;所以可…

最新版 Global Mapper 26 发布

我们在《工作中常用的软件&#xff0c;可直接下载0.3m卫星影像、DEM和土地覆盖数据》一文中&#xff0c;为你分享了GlobalMapper25版本。 现在&#xff0c;该神器的最新版GlobalMapper26已发布&#xff0c;如果这两个版本的软件你都需要&#xff0c;请在文末查看它们的下载方法…

Spring源码分析:bean加载流程

背景 在Spring中&#xff0c;Bean的加载和管理是其核心功能之一&#xff0c;包括配置元数据解析、Bean定义注册、实例化、属性填充、初始化、后置处理器处理、完成创建和销毁等步骤。 源码入口 AbstractBeanFactory#doGetBean 具体源码流程如下&#xff1a; bean加载流程&#…

怎么利用商品详情API接口实现数据获取与应用?

在当今数字化的商业时代&#xff0c;高效获取和利用商品数据对于企业和开发者来说至关重要。商品详情 API 接口为我们提供了一种便捷的方式来获取丰富的商品信息&#xff0c;从而实现各种有价值的应用。本文将深入探讨如何利用商品详情 API 接口实现数据获取与应用。 一、商品…

信号转导的风暴中心:ERK1/2

前 言 ERK1/2是RAF-MEK-ERK信号通路的关键组成部分&#xff0c;在Thr202、Tyr204位点被磷酸化从而激活&#xff0c;进而激活多种与细胞增殖、分化、迁移和血管生成相关的底物&#xff08;超过160种&#xff09;。因此ERK1/2的(Thr202, Tyr204)/(Thr185, Tyr187)磷酸化是ERK激…

从SQL Server过渡到PostgreSQL:理解模式的差异

前言 随着越来越多的企业转向开源技术&#xff0c;商业数据库管理员和开发者也逐渐面临向PostgreSQL迁移的需求。 虽然SQL Server和PostgreSQL共享许多数据库管理系统&#xff08;RDBMS&#xff09;的基本概念&#xff0c;但它们在处理某些结构上的差异可能会让人感到困惑&…

利用Spring Boot实现医疗病历的B2B平台集成

第5章 系统实现 5.1 管理员角色 5.1.1 医院管理 管理员可以在医院管理界面对医院信息进行添加&#xff0c;修改&#xff0c;删除&#xff0c;查询操作。医院管理页面的运行结果如图5-1所示&#xff1a; 图5-1医院管理界面 5.1.2 医院注册 管理员可以在医院注册界面对医院信息…

【LeetCode】动态规划—1312. 让字符串成为回文串的最少插入次数(附完整Python/C++代码)

动态规划—1312. 让字符串成为回文串的最少插入次数 题目描述前言基本思路1. 问题定义目标&#xff1a;举例&#xff1a; 2. 理解问题和递推关系动态规划思路&#xff1a; 3. 解决方法动态规划方法伪代码&#xff1a; 4. 进一步优化5. 小总结 Python代码Python代码解释&#xf…

基于Spring Boot的医疗病历B2B平台开发策略

第4章 系统设计 4.1 系统总体设计 系统不仅要求功能完善&#xff0c;而且还要界面友好&#xff0c;因此&#xff0c;对于一个成功的系统设计&#xff0c;功能模块的设计是关键。由于本系统可执行的是一般性质的学习信息管理工作&#xff0c;本系统具有一般适用性&#xff0c;其…

Java项目:148 基于springboot的校友管理系统

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 校友管理系统项目说明 ​ 本系统是一个学校与毕业生的交流平台。方便校友们了解母校的最新动态&#xff0c;同学的情况&#xff1b;同时学校也可以通过平台了解…

<<迷雾>> 第11章 全自动加法计算机(2)--5 比特存储器 示例电路

可以读/写单个5位二进制数的存储器. info::操作说明 将多个比特单元组合的结果, 整体操作流程类似, 只是可同时读取多位 注: D0~D4 处没有引入写入测试开关, 读者可仿照前面自行引入 primary::在线交互操作链接 https://cc.xiaogd.net/?startCircuitLinkhttps://book.xiaogd.n…

【React】React18核心源码解读

前言 本文使用 React18.2.0 的源码&#xff0c;如果想回退到某一版本执行git checkout tags/v18.2.0即可。如果打开源码发现js文件报ts类型错误请看本人另一篇文章&#xff1a;VsCode查看React源码全是类型报错如何解决。 阅读源码的过程&#xff1a; 下载源码 观察 package…

MySQL 【日期】函数大全(二)

DATE_ADDDATE_FORMATDATE_SUBDATEDIFFDAYDAYNAMEDAYOFMONTHDAYOFWEEK 1、DATE_ADD DATE_ADD(date, value) &#xff1a;在指定的日期/时间上加上指定的时间间隔加并返回新的日期/时间。 DATE_ADD(date, value) DATE_ADD(date, INTERVAL value unit) date&#xff1a;需要操作…