工作记录vue3 echarts地图等 监听浏览器等写法echarts词云

子组件

<template>
  <div>
    <div>【云端报警风险】</div>
    <div ref="target" class="w-full h-full"></div>
  </div>
</template>

<script setup>
import { ref, onMounted,watch } from 'vue';
import * as echarts from "echarts";
// 定义接收父组件传来的值
const props = defineProps({
  data: {
    type: Object,
    required: true,
  },
});
// console.log(props.data);
// 1.初始化
let myChart = null;
const target = ref(null);
onMounted(() => {
  myChart = echarts.init(target.value);
  renderChart();
});

// 2.构建 option 配置对象
const renderChart = () => {
  const options = {
    // 雷达图坐标系配置
    radar: {
      name: {
        textStyle: {
          color: "#05D5FF",
          fontSize: 14
        }
      },
      shape: 'polygon',
      center: ['50%', '50%'],
      radius: '80%',
      startAngle: 120,
      // 轴线
      axisLine: {
        lineStyle: {
          color: 'rgba(2,213,255,.8)'
        }
      },
      // 网格线
      splitLine: {
        show: true,
        lineStyle: {
          with: 1,
          color: 'rgba(5,213,255,.8)'
        }
      },
      // 指示器名称
      indicator: props.data.risks.map(item => ({
        name: item.name,
        max: 100
      })),
      splitArea: {
        show:false
      }
    },
    // 位置、极点
    polar: {
      center: ['50%', '50%'],
      radius:'0%'
    },
    // 坐标角度
    angleAxis: {
      min: 0,
      interval: 5,
      clockwise:false,//刻度逆时针
    },
    // 径向轴
    radiusAxis: {
      min: 0,
      interval: 20,
      splitLine: {
        show:true
      }
    },
    // 图表核心配置
    series: {
      type: 'radar',
      symbol: 'circle',
      symbolSize: 10,
      itemStyle: {
        normal: {
          color:'#05D5FF'
        }
      },
      areaStyle: {
        normal: {
          color: '#05D5FF',
          opacity:0.5
        }
      },
      lineStyle: {
        with: 2,
        color:'#05D5FF'
      },
      label: {
        normal: {
          show:true,
          color: '#05D5FF',
        }
      },
      data: [
        {
          value:props.data.risks.map(item=>item.value)
        }
      ]
    }
  }
  // 3.通过实例.setOptions(option)
  myChart.setOption(options);
};
watch(() => props.data,renderChart)

</script>

<style lang="scss" scoped>

</style>

监听浏览器

const $router = useRouter()

// 获取宽度
const windowSize = () => {
  let width = document.documentElement.clientWidth;
  width<=768?$router.push({ path: "/m" }):""
}
window.addEventListener("resize", windowSize);
windowSize()

echarts 地图

app.vue

<script setup>
import { RouterView } from 'vue-router'
import { provide } from 'vue';
import * as echarts from 'echarts'
import chalk from '@/assets/theme/chalk'
import SocketService from './utils/socket_service'

echarts.registerTheme('chalk', chalk)
provide('echarts', echarts)   //重点
provide('socket', SocketService.Instance)
</script>

<template>
  <RouterView />
</template>

<style scoped></style>


子组件

<script setup>
import { ref, inject, onMounted, onBeforeUnmount } from 'vue';
import useRequest from '@/composables/useRequest'
import chinaJson from '@/assets/map/china.json'
import { getProvinceMapInfo } from '@/utils/map_utils.js'

const echarts = inject('echarts')
const map_chart = ref(null)
let chartInstance = null
const initChart = () => {
    chartInstance = echarts.init(map_chart.value, 'chalk')
    echarts.registerMap('china', chinaJson)
    chartInstance.on('click', async (arg) => {
        const provinceInfo = getProvinceMapInfo(arg.name)
        // console.log(import.meta);    //读取该文件的模块路径
        if (provinceInfo.key) {
            const areaData = await getAreaData(provinceInfo.path)
            echarts.registerMap(provinceInfo.key, { ...areaData })
            chartInstance.setOption({
                geo: {
                    map: provinceInfo.key
                }
            })
        }
    })
}

const getAreaData = (path) => import(/* @vite-ignore */path)

const updataChart = () => {
    const titleFontSize = map_chart.value.offsetWidth / 100 * 3.6
    const option = {
        title: {
            text: "▎商家分布",
            left: 20,
            top: 20,
            textStyle: {
                fontSize: map_chart.value.offsetWidth / 100 * 2.5,
            }
        },
        legend: {
            left: '5%',
            bottom: '5%',
            orient: 'vertical',
            itemWidth: titleFontSize,
            itemHeight: titleFontSize,
            itemGap: titleFontSize,
            textStyle: {
                fontSize: titleFontSize / 2
            }
        },
        geo: {
            type: 'map',
            map: 'china',
            top: "5%",
            bottom: "5%",
            itemStyle: {
                areaColor: '#2E72BF',
                borderColor: '#333'
            }
        },
    }
    chartInstance.setOption(option)
}
const updataChartData = () => {
    const option = {
        series: seriesArr.value
    }
    chartInstance.setOption(option)
}

const allData = ref([])
const seriesArr = ref([])   //放弃使用dataset,有点复杂不会弄。。。
const getData = async () => {
    const res = await useRequest('/map')
    allData.value = res
    seriesArr.value = res.map(i => ({
        type: 'effectScatter',
        rippleEffect: {
            scale: 5,
            brushType: 'stroke'
        },
        name: i.name,
        data: i.children,
        coordinateSystem: 'geo',//在地图使用散点需要加上这项
    }))
    updataChartData()
}

const screenAdapter = () => {
    updataChart()
    chartInstance.resize()
}

onMounted(() => {
    getData()
    initChart()
    screenAdapter()
    window.addEventListener('resize', screenAdapter)
})
onBeforeUnmount(() => {
    window.removeEventListener('resize', screenAdapter)
})
defineExpose({
    screenAdapter
})
</script>

<template>
    <div class="map_container">
        <div class="map_chart" ref="map_chart" @dblclick="updataChart">

        </div>
    </div>
</template>

<style scoped>
.map_container,
.map_chart {
    width: 100%;
    height: 100%;
    overflow: hidden;
}
</style>

使用

 <div class="map" :class="fullScreenStatus.map ? 'fullscreen' : ''">
      <Map ref="map"></Map>
      <span @click="changeSize('map')" class="iconfont enlargement"
        :class="fullScreenStatus.map ? 'icon-compress-alt' : 'icon-expand-alt'"></span>
    </div>


map_utils.js

const nameChange = {
  安徽: 'anhui',
  陕西: 'shanxi1',
  澳门: 'aomen',
  北京: 'beijing',
  重庆: 'chongqing',
  福建: 'fujian',
  甘肃: 'gansu',
  广东: 'guangdong',
  广西: 'guangxi',
  贵州: 'guizhou',
  海南: 'hainan',
  河北: 'hebei',
  黑龙江: 'heilongjiang',
  河南: 'henan',
  湖北: 'hubei',
  湖南: 'hunan',
  江苏: 'jiangsu',
  江西: 'jiangxi',
  吉林: 'jilin',
  辽宁: 'liaoning',
  内蒙古: 'neimenggu',
  宁夏: 'ningxia',
  青海: 'qinghai',
  山东: 'shandong',
  上海: 'shanghai',
  山西: 'shanxi',
  四川: 'sichuan',
  台湾: 'taiwan',
  天津: 'tianjin',
  香港: 'xianggang',
  新疆: 'xinjiang',
  西藏: 'xizang',
  云南: 'yunnan',
  浙江: 'zhejiang'
}

export function getProvinceMapInfo (arg) {
  const path = `/src/assets/map/province/${nameChange[arg]}`
  return {
    key: nameChange[arg],
    path: path
  }
}


socket_service.js

export default class SocketService {
    static instance = null
    static get Instance() {
        if (!this.instance) {
            this.instance = new SocketService()
        }
        return this.instance
    }

    ws = null
    connected = false
    connectRetryCount = 0
    connect() {
        if (!window.WebSocket) {
            return console.log('浏览器不支持websocket');
        }
        this.ws = new WebSocket('ws://localhost:9998')
        this.ws.onopen = () => {
            console.log('服务器连接成功');
            this.connected = true
            this.connectRetryCount = 0
        }
        // 链接失败或连接后断开会调用
        this.ws.onclose = () => {
            console.log('连接服务器失败');
            this.connected = false
            this.connectRetryCount++
            setTimeout(() => {
                this.connect()
            }, this.connectRetryCount * 500)
        }
        this.ws.onmessage = msg => {
            console.log('从服务器获取到了数据');
            // console.log(msg.data);
            const recvData = JSON.parse(msg.data)
            const socketType = recvData.socketType
            if (this.callBackMapping[socketType]) {
                const action = recvData.action
                if (action === 'getData') {
                    const realData = JSON.parse(recvData.data)
                    this.callBackMapping[socketType].call(this, realData)
                } else if (action === 'fullScreen') {

                } else if (action === 'themeChange') {

                }
            }
        }
    }

    callBackMapping = {}
    registerCallBack(socketType, callBack) {
        this.callBackMapping[socketType] = callBack
    }
    unRegisterCallBack(socketType) {
        this.callBackMapping[socketType] = callBack
    }

    sendRetryCount = 0
    send(data) {
        if (this.connected) {
            this.sendRetryCount = 0
            this.ws.send(JSON.stringify(data))
        } else {
            this.sendRetryCount++
            setTimeout(() => {
                this.send(data)
            }, this.sendRetryCount * 500)
        }
    }
}

main.js引入

import { createApp } from 'vue'
import { createPinia } from 'pinia'

import App from './App.vue'
import router from './router'

// 重置样式
import 'normalize.css'

// 字体文件
import './assets/font/iconfont.css'

import './assets/main.css'

import SocketService from './utils/socket_service'
// 开启websocket
SocketService.Instance.connect()

const app = createApp(App)

app.use(createPinia())
app.use(router)

app.mount('#app')



onMounted(() => {
	initChartsCenterOne();
});


// 初始化中间图表1
const initChartsCenterOne = () => {
	const myChart = echarts.init(chartsCenterOneRef.value);
	const option = {
		grid: {
			top: 15,
			right: 15,
			bottom: 20,
			left: 30,
		},
		tooltip: {},
		series: [
			{
				type: 'wordCloud',
				sizeRange: [12, 40],
				rotationRange: [0, 0],
				rotationStep: 45,
				gridSize: Math.random() * 20 + 5,
				shape: 'circle',
				width: '100%',
				height: '100%',
				textStyle: {
					fontFamily: 'sans-serif',
					fontWeight: 'bold',
					color: function () {
						return `rgb(${[Math.round(Math.random() * 160), Math.round(Math.random() * 160), Math.round(Math.random() * 160)].join(',')})`;
					},
				},
				data: [
					{ name: 'vue-next-admin', value: 520 },
					{ name: 'lyt', value: 520 },
					{ name: 'next-admin', value: 500 },
					{ name: '更名', value: 420 },
					{ name: '智慧农业', value: 520 },
					{ name: '男神', value: 2.64 },
					{ name: '好身材', value: 4.03 },
					{ name: '校草', value: 24.95 },
					{ name: '酷', value: 4.04 },
					{ name: '时尚', value: 5.27 },
					{ name: '阳光活力', value: 5.8 },
					{ name: '初恋', value: 3.09 },
					{ name: '英俊潇洒', value: 24.71 },
					{ name: '霸气', value: 6.33 },
					{ name: '腼腆', value: 2.55 },
					{ name: '蠢萌', value: 3.88 },
					{ name: '青春', value: 8.04 },
					{ name: '网红', value: 5.87 },
					{ name: '萌', value: 6.97 },
					{ name: '认真', value: 2.53 },
					{ name: '古典', value: 2.49 },
					{ name: '温柔', value: 3.91 },
					{ name: '有个性', value: 3.25 },
					{ name: '可爱', value: 9.93 },
					{ name: '幽默诙谐', value: 3.65 },
				],
			},
		],
	};
	myChart.setOption(option);
	state.myCharts.push(myChart);
};

const chartsCenterOneRef = ref();

<div class="big-data-down-center-one">
						<div class="big-data-down-center-one-content">
							<div style="height: 100%" ref="chartsCenterOneRef"></div>
						</div>
					</div>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值