Vue3 + TypeScript + Vite + Echarts

Vue3 + TypeScript + Vite + Echarts




1、创建工程

bash 复制代码
npm create vite@latest
bash 复制代码
cd echarts
npm install
npm run dev

2、安装项目依赖模块

bash 复制代码
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

typescript 复制代码
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

typescript 复制代码
import {resolve} from "node:path";

resolve: {
    alias: {
      '@': resolve(__dirname, 'src')
    },
    // 引入文件的时候,可以忽略掉以下文件后缀
    // extensions: ['.js', '.mjs', '.vue', '.json', '.less', '.css']
  },
typescript 复制代码
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

json 复制代码
/* 路径别名 */
"types": ["node"],
"baseUrl": ".",
"paths": {
  "@/*": ["src/*"]
json 复制代码
{
  "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

vue 复制代码
<script setup lang="ts">

</script>

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

<style scoped>

</style>

app.vue

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

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

<style scoped>
</style>
3.2.2 创建路由文件

router.ts

typescript 复制代码
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

typescript 复制代码
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

typescript 复制代码
import 'animate.css'
typescript 复制代码
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

typescript 复制代码
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

typescript 复制代码
import {createPinia} from "pinia";
// 需要注意的是从pinia中解构出来的createPinia是一个函数,挂载前需要先调用执行
// const pinia = createPinia()
// app.use(pinia)
app.use(createPinia())
typescript 复制代码
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

typescript 复制代码
css: {
    preprocessorOptions: {
      scss: {
        // additionalData: '@import "./src/styles/scss_var.scss";'
        additionalData: `@use "./src/styles/scss_var.scss" as *;`,
      }
    }
  }
typescript 复制代码
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

typescript 复制代码
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

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

typescript 复制代码
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

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文件中配置单个组件高度变量

scss 复制代码
// 单个图表 宽度和高度
$chart-width: 100%;
$chart-height: 100%;

5.2 ChartBar.vue

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 组件

vue 复制代码
<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

typescript 复制代码
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

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

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

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

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

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 柱状图

ChartBarView.vue

5.9.1 基础柱状图
vue 复制代码
<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 配置项
vue 复制代码
<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 值轴转换
vue 复制代码
<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 正负条形图
vue 复制代码
<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 折线图

ChartLineView.vue
配置路由

typescript 复制代码
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 基础折线图
vue 复制代码
<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 配置项
vue 复制代码
<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 多坐标轴
vue 复制代码
<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 多坐标轴
vue 复制代码
<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 饼图

ChartPieView.vue
配置路由

typescript 复制代码
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 基础饼图
vue 复制代码
<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 环形图
vue 复制代码
<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 玫瑰图
vue 复制代码
<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
vue 复制代码
<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 数据分割
vue 复制代码
<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 引导线调整
vue 复制代码
<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 默认首页

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

5.12.1 页面布局

scss_var.scss

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

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>

配置路由

typescript 复制代码
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 漏斗图
vue 复制代码
<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 雷达图
vue 复制代码
<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 仪表盘
vue 复制代码
<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 文件中

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

vue 复制代码
<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

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>
vue 复制代码
<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>
相关推荐
小陈phd11 分钟前
OpenCV从入门到精通实战(九)——基于dlib的疲劳监测 ear计算
人工智能·opencv·计算机视觉
zhixingheyi_tian15 分钟前
Spark 之 Aggregate
大数据·分布式·spark
PersistJiao16 分钟前
Spark 分布式计算中网络传输和序列化的关系(一)
大数据·网络·spark
活宝小娜1 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点1 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow1 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o1 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
Guofu_Liao1 小时前
大语言模型---LoRA简介;LoRA的优势;LoRA训练步骤;总结
人工智能·语言模型·自然语言处理·矩阵·llama
开心工作室_kaic2 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā2 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue