- let container = document.querySelector('.app')
- let myChart = echarte.init(container) // 初始化图表实例
- <body>
- <div class="app" style="width: 600px;height: 400px;">
-
- </div>
- <script src="
- https://cdn.jsdelivr.net/npm/echarts@5.4.2/dist/echarts.min.js
- "></script>
- <script>
- console.log(echarts, 123)
- // 绘制echarts图标的流程
- let container = document.querySelector('.app')
- let myChart = echarts.init(container) // 初始化图表实例
- myChart.setOption({
- // 传入配置对象,通过这个配置对象确认绘制的图表内容
- xAxis: {
- // 默认情况下,x粥通常为category类型,y轴一般为value
- type: 'category',
- data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
- },
- yAxis: {
- type: 'value'
- },
- // series决定绘制一个什么类型的图表
- series: [ // 一个框只绘制一个图像时可以不用写成数组
- {
- data: [820, 932, 901, 934, 1290, 1330, 1320],/* 数据 */
- type: 'line', /* 数据显示类型 */
- areaStyle:{
- color:"purple",
- opacity:1,/* 颜色透明度 */
- },
- smooth: true, /* 光滑 */
- itemStyle:{
- opacity:0 // 点透明度
- },
- }
- ]
- })
- </script>
- </body>
在网站的文档中找到配置项手册,




- myChart.setOption({
- // 传入配置对象,通过这个配置对象确认绘制的图表内容
- xAxis: {
- // 默认情况下,x粥通常为category类型,y轴一般为value
- type: 'category',
- data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
- },
- yAxis: {
- type: 'value',
- splitLine:{
- show: false // 去掉柱状图背景的分隔线
- }
- },
- // series决定绘制一个什么类型的图表
- series: [
- {
- data: [820, 932, 901, 934, 1290, 1330, 1320],/* 数据 */
- type: 'bar', /* 数据显示类型 */
-
- }
- ],
- tooltip:{}, // 鼠标移上去显示标签
- })
npm install echarts
开始前准备
给vue的prototype原型对象挂载的属性,可以在入口中给每个组件实例都注入一些成员。
- import Vue from 'vue'
- import App from './App.vue'
- import * as echarts from 'echarts'
- import vcharts from 'vue-echarts'
- Vue.component('v-chart', vcharts) // 注册全局组件v-chart
- Vue.config.productionTip = false
- // 给vue的prototype原型对象挂载的属性,可以在入口中给每个组件实例都注入一些成员
- Vue.prototype.$echarts = echarts
-
- new Vue({
- render: h => h(App)
- }).$mount('#app')
封装组件,初始化图表可以通过封装好的组件来完成。使用封装好的组件可以不再进行原本的初始化内容

改为了

input为v-model绑定的data
在视图中需要写入:option="option"
- <div class="wrapper">
- <div class="container" >
- <v-chart :option="option"></v-chart>
- </div>
- <el-button>这是按钮</el-button>
- <el-input v-model="input" placeholder="请输入内容"></el-input>
- </div>
- // 全局注册组件
- npm install vue-echarts
- // ui组件vue2和vue3
- npm i element-ui
- npm i element-plus
- // reset-css 初始化全局样式组件
- npm i reset-css


- // main
- import Vue from 'vue'
- import App from './App.vue'
- import * as echarts from 'echarts'
- import './plugins/element-ui' // 引入组件库
- import './plugins/vue-echarts'
- import 'reset-css' // 引入清除默认样式css
- Vue.config.productionTip = false
- // 给vue的prototype原型对象挂载的属性,可以在入口中给每个组件实例都注入一些成员
- Vue.prototype.$echarts = echarts
-
- new Vue({
- render: h => h(App)
- }).$mount('#app')
-
- // element-ui 实现组件的按需引入
- import Vue from 'vue'
- import 'element-ui/lib/theme-chalk/index.css'
- import { Button, Input } from 'element-ui' // 按需引入el的组件
- Vue.use(Button)
- Vue.use(Input) // 组件引入后需要在下面注册一下
-
- // vue-echarts 实现组件的全局注册
- import Vue from 'vue'
- import vcharts from 'vue-echarts'
- Vue.component('v-chart', vcharts) // 注册全局组件v-chart


在.eslintrc.js中的rules里书写一个'vue/multi-word-component-names': 0,将命名必须要大驼峰的规则去掉
- <template>
- <div class="app">
- <TopComp/>
- <SecondComp/>
- <ThirdComp/>
- <MapComp/>
- </div>
- </template>
-
- <script>
- import TopComp from './components/TopComp'
- import SecondComp from './components/SecondComp'
- import ThirdComp from './components/ThirdComp'
- import MapComp from './components/MapComp'
- export default {
- components: {
- TopComp,
- SecondComp,
- ThirdComp,
- MapComp
- }
- }
- /* 公共样式 */
- html,body {
- background-color: #eee;
- }
- <template>
- <div class="commom-card">
- <div class="title">{{ title }}</div>
- <div class="value">{{ value }}</div>
- <div class="chart">
- <slot></slot>
- </div>
- <div class="line"></div>
- <div class="footer">
- <slot name="footer"></slot>
- </div>
- </div>
- </template>
- <script>
- export default {
- props: ['title', 'value']
- }
- </script>
- span.increase{
- display: inline-block;
- width: 0;
- height: 0;
- border-width: 4px;
- border-color: transparent transparent green transparent;
- border-style: solid;
- margin-left: 10px;
- transform: translateY(-50%);
- }
新建TotalSale.vue,使用CommonCard组件写卡片中的内容
- <template>
- <div class="total-sale">
- <CommonCard title="累计销售额" :value="reportData.salesToday">
- <div>
- <span>日同比</span>
- <span class="css-1">{{reportData.salesGrowLastDay}}%</span>
- <span class="increase"></span>
- </div>
- <div>
- <span>月同比</span>
- <span class="css-1">{{reportData.saleSGrowLastMonth}}%</span>
- <span class="increase"></span>
- </div>
- <template #footer>
- <span>昨日销售额</span>
- <span class="css-1">¥{{reportData.salesLastDay }}</span>
- </template>
- </CommonCard>
- </div>
- </template>
绘制第二个卡片的图TotalOrder.vue
- mixins: [CommonCardMixin],
- data () {
- return {
- option: null
- }
- },
- mounted () {},
- watch: {
- reportData (newValue) {
- this.renderChart(newValue.orderTrend)
- }
- },
- methods: {
- renderChart (data) {
- this.option = {
- xAxis: {
- type: 'category',
- show: false,
- boundaryGap: false
- },
- yAxis: {
- type: 'value',
- show: false
- },
- // 在一些宽高很小的容器上绘图的时候 可以将网格和容器靠近
- grid: {
- left: 0,
- top: 0,
- right: 0,
- bottom: 0
- },
- series: {
- type: 'line',
- data,
- areaStyle: {
- color: 'purple'
- },
- lineStyle: {
- width: 0
- },
- itemStyle: {
- opacity: 0
- },
- smooth: true
- }}}}
- <template>
- <div class="total-order">
- <CommonCard title="累积订单额" value="13145">
- <v-chart :option="option" />
- <template #footer>
- <span>昨日销售额</span>
- <span class="css-1">¥ 12768</span>
- </template>
- </CommonCard>
- </div>
- </template>
绘制第三个卡片的图,创建TodayUser.vue
- <template>
- <div class="today-user">
- <CommonCard title="今日用户交易数" :value="reportData.userToday">
- <v-chart :option="option"/>
- <template #footer>
- <span>退货率</span>
- <span class="css-1">{{reportData.returnRate}}%</span>
- </template>
- </CommonCard>
- </div>
- </template>
- <script>
- import CommonCardMixin from '../../mixins/CommonCardMixin.js'
-
- export default {
- mixins: [CommonCardMixin],
- data () {
- return {
- option: null
- }
- },
- methods: {
- renderChart (data) {
- this.option = {
- xAxis: {
- type: 'category',
- show: false,
- data: [
- '00:00',
- '03:00',
- '05:00',
- '07:00',
- '09:00',
- '11:00',
- '13:00',
- '15:00',
- '17:00',
- '19:00',
- '21:00',
- '23:00'
- ]
- },
- yAxis: {
- type: 'value',
- show: false
- },
- tooltip: {},
- grid: {
- left: 0,
- right: 0,
- top: 0,
- bottom: 0
- },
- series: {
- type: 'bar',
- name: '实时交易量',
- data,
- barWidth: '60%'
- }
- }
- }
- },
- mounted () {},
- watch: {
- reportData (newValue) {
- this.renderChart(newValue.orderUserTrend)
- }
- }
- }
- series: [
- {
- type: 'bar',
- name: '上月平台用户数',
- data: [data1],
- barWidth: 10,
- itemStyle: {
- color: 'green'
- },
- stack: '1'
- }, {
- type: 'bar',
- name: '本月平台用户数',
- data: [data2],
- itemStyle: {
- color: '#ddd'
- },
- barWidth: 10,
- stack: '1'
- }, {
- type: 'custom',
- renderItem: (params, api) => {
- // 绘制三角形(利用svg路径) 确定2个是: 确定三角形位置 如何绘制2个三角形本身
- const endPoint = api.coord([api.value(0), 0])
- return {
- type: 'group',
- children: [
- {
- type: 'path',
- shape: {
- d: 'M511.744 319.999l-383.744 383.744h767.488l-383.744-383.744z',
- x: endPoint[0] - 5,
- y: 35,
- width: 10,
- height: 10,
- layout: 'cover'
- },
- style: {
- fill: 'green'
- }
- },
- {
- type: 'path',
- shape: {
- d: 'M889.696 320.8H158.848l365.504 365.536 365.344-365.536z',
- x: endPoint[0] - 5,
- y: 5,
- width: 10,
- height: 10,
- layout: 'cover'
- },
- style: {
- fill: 'green'
- }
- }
- ]
- }
- },
- data: [data1]
- }
写接口http://project.x-zd.net:3001/apis/reportdata
- // 封装发送请求的axios
- import axios from 'axios'
- const request = axios.create({
- baseURL: 'http://project.x-zd.net:3001/apis',
- timeout: 3000
- })
- // 利用axios拦截器处理一下返回的数据(只想要返回的data字段)
- request.interceptors.response.use((res) => {
- return res.data
- }, (err) => { return Promise.reject(err) })
- export default request
- // 封装请求数据的具体方法
- import request from './axios'
- export const getReportData = () => request.get('/reportdata')
- import { getReportData } from '../../api'
- export default {
- data () {
- return {
- reportData: {}
- }
- },
- components: { TotalSale, TotalOrder, TodayUser, TotalUser },
- async mounted () {
- const res = await getReportData()
- this.reportData = res
- }
- }
- <template>
- <div class="top-comp">
- <el-row :gutter="20">
- <el-col :span="6">
- <el-card shadow="hover">
- <TotalSale :reportData="reportData"/> <!-- 示例,分别传给四个组件 -->
- <template>
- <div class="total-user">
- <CommonCard title='累计用户数' :value="reportData.totalUser">
- <v-chart :option="option"/>
- <template #footer>
- <div class="wrapper">
- <div>
- <span>日同比</span>
- <span class="css-1">{{reportData.userGrowLastDay}}%</span>
- <span class="increase"></span>
- </div>
- <div>
- <span>月同比</span>
- <span class="css-1">{{reportData.userGrowLastMonth}}%</span>
- <span class="increase"></span>
- export default {
- mixins: [CommonCardMixin],
- data () {
- return {
- option: null
- }
- },
- methods: {
- renderChart (data1, data2) {
- this.option = {
- xAxis: {
- type: 'value',
- show: false
- },
- yAxis: {
- type: 'category',
- show: false
- },
- grid: {...},
- series: [
- {
- type: 'bar',
- name: '上月平台用户数',
- data: [data1],
- barWidth: 10,
- itemStyle: {
- color: 'green'
- },
- stack: '1'
- }, {
- type: 'bar',
- name: '本月平台用户数',
- data: [data2],
- itemStyle: {
- color: '#ddd'
- },
- barWidth: 10,
- stack: '1'
- }, {
- type: 'custom',
- ......
- },
- data: [data1]
- }
- ]
- }
- }
- },
- mounted () {
- // this.renderChart()
- },
- watch: {
- reportData (newValue) {
- this.renderChart(newValue.userLastMonth, newValue.userToday)
- }
- }
- }
四个头部卡片中拥有一些相同逻辑,并且都接受了rportData,可以将相同的逻辑使用mixin(混入,用来提取公共逻辑)抽离出来。就不用再在不同的组件中重复书写相同的逻辑。
- import CommonCard from '../components/TopComp/CommonCard.vue'
- export default {
- props: ['reportData'],
- components: {
- CommonCard
- }
- }
- import CommonCardMixin from '../../mixins/CommonCardMixin.js'
-
- export default {
- mixins: [CommonCardMixin],
- data () {
- return {
- option: null
- }
- },
- <template>
- <div class="second-comp">
- <el-card class="box-card">
- <template #header>
- <el-menu
- :default-active="activeIndex"
- class="el-menu-demo"
- mode="horizontal"
- @select="handleSelect"
- >
- <el-menu-item index="1">销售额</el-menu-item>
- <el-menu-item index="2">访问量</el-menu-item>
- </el-menu>
- export default {
- data () {
- return {
- activeIndex: '1',
- import Vue from 'vue'
- import 'element-ui/lib/theme-chalk/index.css'
- import { Button, Input, Row, Col, Card, Menu, MenuItem, RadioButton, RadioGroup, DatePicker } from 'element-ui'
- Vue.use(Menu)
- Vue.use(MenuItem)
- Vue.use(RadioButton)
- Vue.use(RadioGroup)
- Vue.use(DatePicker)
- export default {
- data () {...},
- methods: {
- handleSelect (index) {
- this.activeIndex = index// 让选中的菜单激活
- ...},
- ...
- <template #header>
- ...
- <div class="right">
- <el-radio-group v-model="time">
- <el-radio-button label="今日"></el-radio-button>
- <el-radio-button label="本周"></el-radio-button>
- <el-radio-button label="本月"></el-radio-button>
- <el-radio-button label="今年"></el-radio-button>
- </el-radio-group>
- <el-date-picker
- v-model="pickerTime"
- type="daterange"
- align="right"
- unlink-panels
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- :picker-options="pickerOptions"
- >
- </el-date-picker>
- </div>
- </template>
- export default {
- data () {
- return {
- activeIndex: '1',
- time: '今日',
- pickerTime: '',
- pickerOptions: {
- shortcuts: [
- {
- text: '最近一周',
- onClick (picker) {
- const end = new Date()
- const start = new Date()
- start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
- picker.$emit('pick', [start, end])
- }
- },
- {
- text: '最近一个月',
- onClick (picker) {
- const end = new Date()
- const start = new Date()
- start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
- picker.$emit('pick', [start, end])
- }
- },
- {
- text: '最近三个月',
- onClick (picker) {
- const end = new Date()
- const start = new Date()
- start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
- picker.$emit('pick', [start, end])
- }
- }
- ]
- },
- <template #default>
- <div class="content">
- <div class="left-chart">
- <v-chart :option="option" />
- </div>
- <div class="right-list">
- <div class="list-title">排行榜</div>
- <div class="list-item" v-for="item in rankData" :key="item.no" >
- <span :class="{'top-3':item.no<=3}">{{ item.no }}</span>
- <span>{{ item.title }}</span>
- <span>{{ item.sales }}</span>
- </div>
- </div>
- </div>
- </template>
- export default {
- data () {
- return {...
- option: {},}}
- .content {
- display: flex;
- .left-chart {
- flex: 0 0 70%;
- height: 434px;
- }
- .right-list {...}
- }
- export default {
- data () {
- return {...}
- },
- methods: {
- handleSelect (index) {...},
- renderChart (data1, data2) {
- this.option = {
- title: {
- text: '年度销售额',
- textStyle: {
- fontWeight: 600,
- fontSize: 14
- }
- },
- xAxis: {
- type: 'category',
- data: data1,
- axisTick: {
- alignWithLabel: true
- }
- },
- yAxis: {
- type: 'value',
- splitLine: {
- lineStyle: {
- type: 'dotted'
- }
- }
- },
- grid: {
- left: 40
- },
- series: {
- type: 'bar',
- data: data2,
- barWidth: '40%'
- },
- color: 'skyblue'
- }
- }
- },
- async mounted () {
- const res = await getSaleData()
- this.saleData = res
- this.rankData = res.saleRank
- this.renderChart(this.saleData.saleFulleYearAxis,
- this.saleData.saleFulleYear)
- }
- }
- <template>
- <div class="second-comp">
- <el-card class="box-card">
- <template #header>....</template>
- <template #default>
- <div class="content">
- <div class="left-chart"><v-chart :option="option" /></div>
- <div class="right-list">
- <div class="list-title">排行榜</div>
- <div class="list-item"
- v-for="item in rankData"
- :key="item.no" >
- <span :class="{'top-3':item.no<=3}">{{ item.no }}</span>
- <span>{{ item.title }}</span>
- <span>{{ item.sales }}</span>
- </div>
- </div>
- </div>
- </template>
- .content {
- display: flex;
- .left-chart {...}
- .right-list {
- flex: 1;
- .list-title {
- margin-bottom: 10px;
- font-size: 14px;
- font-weight: 600;
- }
- .list-item {
- margin: 20px 0px;
- display: flex;
- gap: 20px;
- span {
- font-size: 14px;
- color: #464545;
- }
- span:nth-child(2) {
- flex: 1;
- }
- span:nth-child(1) {
- width: 20px;
- height: 20px;
- border-radius: 10px;
- text-align: center;
- line-height: 20px;
- }
- .top-3{
- background-color:#09b3f7 ;
- color:#fff
- }
- }
- }
- }
- // 封装请求数据的具体方法
- import request from './axios'
- export const getReportData = () => request.get('/reportdata')
- export const getSaleData = () => request.get('/saledata')
- import { getSaleData } from '@/api'
- export default {
- data () {
- return {
- activeIndex: '1',
- time: '今日',
- pickerTime: '',
- pickerOptions: {...},
- option: {},
- saleData: null,
- rankData: []
- }
- },
- <div class="right-list">
- <div class="list-title">排行榜</div>
- <div class="list-item" v-for="item in rankData" :key="item.no" >
- <span :class="{'top-3':item.no<=3}">{{ item.no }}</span>
- <span>{{ item.title }}</span>
- <span>{{ item.sales }}</span>
- </div>
- </div>
- export default {
- data () {
- return {
- ...
- saleData: null,
- rankData: []
- }
- },
- methods: {
- handleSelect (index) {
- this.activeIndex = index// 让选中的菜单激活
- if (index === '1') {
- this.rankData = this.saleData.saleRank
- this.renderChart(this.saleData.saleFulleYearAxis,
- this.saleData.saleFulleYear)
- } else { // 此处yead为接口名写错,是可以使用的
- this.rankData = this.saleData.visitRank
- this.renderChart(this.saleData.visitFullYeadAxis,
- this.saleData.visitFullYear)
- }
- },
可以不拆成两个组件,统一写在项目结构中(也可以拆开写成两个组件,主要是看有没有别的地方也用了类似格式
- .third-comp {
- margin-top: 20px;
- display: flex;
- gap: 20px;
- & > div {
- flex: 1;
- }
- <template>
- <div class="third-comp">
- <div class="left">
- <el-card shadow="hover">
- <template #header>
- <div>关键词搜索</div>
- </template>
- <div class="main">
- <div class="charts">
- <div class="left-chart">...</div>
- <div class="right-chart">...</div>
- </div>
- <div class="table">...</div>
- </div>
- </el-card>
- </div>
- <div class="right"></div>
- </div>
- </template>
- <div class="main">
- <div class="charts">
- <div class="left-chart">
- <div class="title">搜索用户量</div>
- <div class="number">{{ totalUser }}</div>
- <v-chart :option="option1" />
- </div>
- <div class="right-chart">
- <div class="title">搜索量</div>
- <div class="number">{{ totalSearch }}</div>
- <v-chart :option="option2" />
- </div>
- </div>
- import Vue from 'vue'
- import 'element-ui/lib/theme-chalk/index.css'
- import { ... Table, TableColumn, Pagination } from 'element-ui'
- ...
- Vue.use(Table)
- Vue.use(TableColumn)
- Vue.use(Pagination)
- <div class="main">
- <div class="charts">
- <div class="left-chart">... </div>
- <div class="right-chart">... </div>
- </div>
- <div class="table">
- <el-table :data="tableData">
- <el-table-column></el-table-column>*4
- </el-table>
- <div class="main">
- <div class="charts">
- <div class="left-chart">... </div>
- <div class="right-chart">... </div>
- </div>
- <div class="table">
- <el-table :data="tableData">...</el-table>
- <el-pagination
- background
- layout="prev, pager, next"
- :total="20"
- :page-size="pageSize"
- @current-change="currentChange"
- >
- </el-pagination>
- </div>
- </div>
- import request from './axios' ...
- export const getKeyWordData = () => request.get('/keyworddata')
- export default {
- data () {...}
- },
- methods: {
- currentChange (page) {...}
- },
- async mounted () {
- const res = await getKeyWordData()
- this.totalData = res
- // 初始状态下,tableData显示前六条数据
- this.tableData = this.totalData.slice(0, this.pageSize)
- }
- }
- <el-table :data="tableData">
- <el-table-column prop="rank"
- label="排名" width="60"></el-table-column>
- <el-table-column prop="keyWord"
- label="关键词" align="center"></el-table-column>
- <el-table-column prop="totalSearch"
- label='总搜索量' align="center"></el-table-column>
- <el-table-column prop="totalUser"
- label="搜索用户数" align="center"></el-table-column>
- </el-table>
- <div class="table">
- <el-table :data="tableData">... </el-table>
- <el-pagination
- background
- layout="prev, pager, next"
- :total="20"
- :page-size="pageSize"
- @current-change="currentChange"
- >
- </el-pagination>
- </div>
- export default {
- data () {
- return {
- option1: {},
- option2: {},
- tableData: [],
- totalData: {},
- pageSize: 6
- }},
- methods: {
- currentChange (page) {
- // page为当前选中的页码
- this.tableData = this.totalData.slice(this.pageSize * (page - 1),
- this.pageSize * page)}},
- async mounted () {...}}
- export default {
- data () {
- return {
- option1: {},
- option2: {},
- tableData: [],
- totalData: {},
- pageSize: 6
- }
- },
- methods: {
- currentChange (page) {
- // page为当前选中的页码
- this.tableData = this.totalData.slice(this.pageSize * (page - 1), this.pageSize * page)
- },
- renderChart1 (data) {
- this.option1 = {
- xAxis: {
- type: 'category',
- show: false,
- boundaryGap: false
- },
- yAxis: {
- type: 'value',
- show: false
- },
- grid: {
- left: 0,
- right: 0,
- top: 0,
- bottom: 0
- },
- series: {
- type: 'line',
- data,
- areaStyle: {
- color: 'skyblue'
- },
- itemStyle: {
- opacity: 0
- },
- smooth: true
- }
- }
- },
- renderChart2 (data) {
- this.option2 = {
- xAxis: {
- type: 'category',
- show: false,
- boundaryGap: false
- },
- yAxis: {
- type: 'value',
- show: false
- },
- grid: {
- left: 0,
- right: 0,
- top: 0,
- bottom: 0
- },
- series: {
- type: 'line',
- data,
- areaStyle: {
- color: 'skyblue'
- },
- itemStyle: {
- opacity: 0
- },
- smooth: true
- }
- }
- }
- },
- async mounted () {
- ...
- this.renderChart1(this.totalData.map(item => item.totalUser).slice(0, 10).reverse())
- this.renderChart2(this.totalData.map(item => item.totalSearch).slice(0, 10).reverse())
- }
- computed: {
- totalSearch () {
- return this.totalData.reduce((pre, cur) => {
- return pre + cur.totalSearch
- }, 0)
- },
- totalUser () {
- return this.totalData.reduce((pre, cur) => {
- return pre + cur.totalUser
- }, 0)
- }
- },
整体框架
- <template>
- <div class="third-comp">
- <div class="left">...</div>
- <div class="right">
- <el-card>
- <template #header>
- .right {
- .el-card {
- height: 100%;
- ::v-deep .el-card__body {
- height: 558px;
- .pie-chart {
- height: 100%;
- }
- }
- ::v-deep .el-card__header {
- position: relative;
- .el-radio-group {
- position: absolute;
- right: 2%;
- top: 10%;
- }
- }
- }
- }
- <div class="right">
- <el-card>
- <template #header>
- <div class="css-2">分类销售排行</div>
- <el-radio-group v-model="radio" @input="handleRadio">
- <el-radio-button label="品类"></el-radio-button>
- <el-radio-button label="商品"></el-radio-button>
- </el-radio-group>
- </template>
- <div class="pie-chart">
- <v-chart :option="pieChartOption" />
- </div>
- </el-card>
- </div>
- renderPieChart (data) {
- // 需要给data添加上一个name字段 从而可以让legend读到
- data = data.map((item) => {
- item.name = item.title + '|' + item.value
- return item
- })
- const totalSale = data.reduce((pre, cur) => {
- return pre + cur.value
- }, 0)
- this.pieChartOption = {
- title: [
- {
- text: '品类分布',
- textStyle: {
- fontSize: 14,
- color: '#666'
- },
- left: 20,
- top: 20
- },
- {
- text: '累计订单量',
- subtext: totalSale,
- x: '40%',
- y: '45%',
- textAlign: 'center',
- textStyle: {
- fontSize: 14,
- color: '#999'
- },
- subtextStyle: {
- fontSize: 28,
- color: '#333'
- }
- }
- ],
- renderPieChart (data) {
- // 需要给data添加上一个name字段 从而可以让legend读到
- data = data.map((item) => {
- item.name = item.title + '|' + item.value
- return item
- })
- const totalSale = data.reduce((pre, cur) => {
- return pre + cur.value
- }, 0)
- this.pieChartOption = {
- title: [...],
- series: {
- name: '品类分布',
- type: 'pie',
- data,
- radius: ['45%', '60%'],
- center: ['40%', '50%'],
- itemStyle: {
- borderWidth: 8,
- borderColor: '#fff'
- },
- label: {
- show: true,
- position: 'outside',
- formatter: (params) => {
- return params.data.title
- }
- }
- },
- renderPieChart (data) {
- // 需要给data添加上一个name字段 从而可以让legend读到
- data = data.map((item) => {
- item.name = item.title + '|' + item.value
- return item
- })
- const totalSale = data.reduce((pre, cur) => {
- return pre + cur.value
- }, 0)
- this.pieChartOption = {
- title: [...],
- series: {...},
- tooltip: {
- trigger: 'item',
- formatter: (params) => {
- return params.seriesName + '
' + params.marker + params.data.title + '
' + params.marker + '销售额' + params.data.value - }
- },
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
- async mounted () {
- const _res = await getCategoryData()
- this.categoryData = _res
- this.renderPieChart(this.categoryData.data1)
- }
- renderPieChart (data) {
- // 需要给data添加上一个name字段 从而可以让legend读到
- data = data.map((item) => {
- item.name = item.title + '|' + item.value
- return item
- })
- const totalSale = data.reduce((pre, cur) => {
- return pre + cur.value
- }, 0)
- this.pieChartOption = {
- title: [...],
- series: {...},
- tooltip: {...},
- legend: {
- // 会自动读取data数据的 name字段
- left: '80%',
- top: 'top',
- textStyle: {
- color: '#888'
- }
- }
- }
- },
- computed: {
- totalSearch () {
- return this.totalData.reduce((pre, cur) => {
- return pre + cur.totalSearch
- }, 0)
- },
- totalUser () {
- return this.totalData.reduce((pre, cur) => {
- return pre + cur.totalUser
- }, 0)
- }
- },
- export default {
- data () {...},
- methods: {
- handleRadio (label) {
- if (label === '品类') {
- this.renderPieChart(this.categoryData.data1)
- } else {
- this.renderPieChart(this.categoryData.data2)
- }
- }
- },
在百度地图开发者平台中的应用管理中创建应用

拆分为三个组件来写
将三个组件vue引入index,注册,写在视图中,添加样式
在需要绘图的组件上规定宽高,否则无法撑起盒子
- <head>
- ....
- <script src="https://api.map.baidu.com/api?v=2.0&ak=秘钥"></script>
- </head>
- <script>
- import 'echarts/extension/bmap/bmap'
- export default {
- export default {
- data () {
- return {
- option: null
- }
- },
- methods: {
- renderChart () {
- this.option = {
- bmap: {
- key: '秘钥',
- center: [108.954355, 34.346721],
- zoom: 5,
- roam: false, // 是否可以缩放
- mapStyle: {...}
- }
- }
- }
- },
- mounted () {
- this.renderChart()
- }
- styleJson: [
- {
- featureType: 'water',
- elementType: 'all',
- stylers: {
- color: '#d1d1d1'
- }
- },
- {
- featureType: 'land',
- elementType: 'all',
- stylers: {
- color: '#f3f3f3'
- }
- },
- {
- featureType: 'railway',
- elementType: 'all',
- stylers: {
- visibility: 'off'
- }
- },
- {
- featureType: 'highway',
- elementType: 'all',
- stylers: {
- color: '#fdfdfd'
- }
- },
- {
- featureType: 'highway',
- elementType: 'labels',
- stylers: {
- visibility: 'off'
- }
- },
- {
- featureType: 'arterial',
- elementType: 'geometry',
- stylers: {
- color: '#fefefe'
- }
- },
- {
- featureType: 'arterial',
- elementType: 'geometry.fill',
- stylers: {
- color: '#fefefe'
- }
- },
- {
- featureType: 'poi',
- elementType: 'all',
- stylers: {
- visibility: 'off'
- }
- },
- {
- featureType: 'green',
- elementType: 'all',
- stylers: {
- visibility: 'off'
- }
- },
- {
- featureType: 'subway',
- elementType: 'all',
- stylers: {
- visibility: 'off'
- }
- },
- {
- featureType: 'manmade',
- elementType: 'all',
- stylers: {
- color: '#d1d1d1'
- }
- },
- {
- featureType: 'local',
- elementType: 'all',
- stylers: {
- color: '#d1d1d1'
- }
- },
- {
- featureType: 'arterial',
- elementType: 'labels',
- stylers: {
- visibility: 'off'
- }
- },
- {
- featureType: 'boundary',
- elementType: 'all',
- stylers: {
- color: '#fefefe'
- }
- },
- {
- featureType: 'building',
- elementType: 'all',
- stylers: {
- color: '#d1d1d1'
- }
- },
- {
- featureType: 'label',
- elementType: 'labels.text.fill',
- stylers: {
- color: '#999999'
- }
- }
- ]
在地图上写散点图,title下面写。把series写为数组对象,一组普通散点,一组波纹散点
- export default {
- data () {
- return {
- option: null
- }
- },
- methods: {
- renderChart (data) {
- this.option = {
- bmap: {...},
- title: {
- text: '新中地网点地图',
- left: 'center'
- },
- series: [
- {
- name: '新中地外卖',
- coordinateSystem: 'bmap',
- type: 'scatter',
- data
- }, {}
- ]
- import request from './axios' ...
- export const getMapData = () => request.get('/mapdata')
- import { getMapData } from '@/api'
- function converData (city, geodata) {
- // city => [{name:'海门',value:10},{}...]
- // geodata => {'海门':[80,100],....}
- // res => [{name:'海门',value:[80,100,10]},...]
- const res = []
- city.forEach(item => {
- // item.name为城市名称,可以根据城市名称找到经纬度
- const geo = geodata[item.name]
- if (geo) {
- res.push({
- name: item.name,
- value: geo.concat(item.value) // 拼接数组
- })
- }
- methods: {
- renderChart (data) {
- this.option = {
- bmap: {...},
- title: {...},
- tooltip: {
- trigger: 'item'
- },
- series: [
- {
- name: '新中地外卖',
- coordinateSystem: 'bmap',
- type: 'scatter',
- data,
- encode: {
- value: 2
- },
- symbolSize (value) {
- return value[2] / 10
- }
- }, {}
- ]
- }, {
- name: '新中地外卖',
- coordinateSystem: 'bmap',
- type: 'effectScatter',
- data: data.sort((a, b) => {
- return b.value[2] - a.value[2]
- }).slice(0, 10),
- encode: {
- value: 2
- },
- symbolSize (value) {
- return value[2] / 10
- },
- rippleEffect: {
- brushTypy: 'storke',
- color: 'purple'
- },
- export default {
- data () {},
- methods: {
- renderChart (data) {
- this.option = {...
- series: [
- {...}, {
- name: '新中地外卖',
- coordinateSystem: 'bmap',
- type: 'effectScatter',
- data: data.sort((a, b) => {
- return b.value[2] - a.value[2]
- }).slice(0, 10),
- encode: {
- value: 2
- },
- symbolSize (value) {
- return value[2] / 10
- },
- rippleEffect: {
- brushTypy: 'storke',
- color: 'purple'
- },
- tooltip: {
- formatter: (params) => {
- return params.data.name + '销售额'
- + params.data.value[2]
- },
- textStyle: {
- color: 'green'}}}]}}}}
LiquidFill.vue
在npm中搜索npm install echarts-liquidfill
- <script>
- import 'echarts-liquidfill'
- export default {...
- export default {
- data () {
- return {
- option: {}
- }
- },
- methods: {
- renderChart (data) {
- this.option = {
- series: {
- type: 'liquidFill',
- data: [data],
- radius: '80%',
- color: ['red'],
- amplitude: '4%',
- outline: {
- borderDistance: 2,
- itemStyle: {
- borderWidth: 2
- }
- ...
- <script>
- import { getReportData } from '@/api'
- export default {
- ...
- async mounted () {
- const res = await getReportData()
- this.renderChart((+res.salesGrowLastDay / 100).toFixed(2))
- }
- }
WordCloud.vue
npm install echarts-wordcloud
在仓库地址中寻找使用说明
- <script>
- import 'echarts-wordcloud'
- export default {...
- <template>
- <v-chart :option="option" />
- </template>
- <script>
- import 'echarts-wordcloud'
- import { getKeyWordData } from '@/api'
- export default {
- data () {
- return {
- option: {}
- }
- },
- methods: {
- renderChart (data) {
- this.option = {
- series: {
- type: 'wordCloud',
- shape: 'cardioid',
- data,
- ...
- <script>
- import 'echarts-wordcloud'
- import { getKeyWordData } from '@/api'
- export default {
- data () {...},
- methods: {...},
- async mounted () {
- let res = await getKeyWordData()
- res = res.slice(0, 6).map(item => {
- return {
- name: item.keyWord,
- value: item.totalSearch
- }
- })
- this.renderChart(res)
- }
- }
- </script>
- export default {
- data () {...},
- methods: {
- renderChart (data) {
- this.option = {
- series: {
- type: 'wordCloud',
- shape: 'cardioid',
- data,
- width: '100%',
- height: '100%',
- textStyle: {
- // Color can be a callback function or a color string
- color: function () {
- // Random color
- return 'rgb(' + [
- Math.round(Math.random() * 160),
- Math.round(Math.random() * 160),
- Math.round(Math.random() * 160)
- ].join(',') + ')'
- }
- },
- emphasis: {
- focus: 'self',
- textStyle: {
- textShadowBlur: 5,
- textShadowColor: '#333'
- }
- }
- },
- tooltip: {} // 空数组即可,只要出现
- }
- }
- },