<!-- * 随机数相关 --> <script setup lang="ts"> import { onMounted, ref, reactive, nextTick, onBeforeUnmount } from 'vue'; import { getRandomInt } from 'src/common/utils'; // echarts import * as echarts from 'echarts/core'; import { GridComponent, GridComponentOption, LegendComponent, LegendComponentOption, } from 'echarts/components'; import { BarChart, BarSeriesOption } from 'echarts/charts'; import { CanvasRenderer } from 'echarts/renderers'; echarts.use([GridComponent, LegendComponent, BarChart, CanvasRenderer]); type EChartsOption = echarts.ComposeOption< GridComponentOption | LegendComponentOption | BarSeriesOption >; const min = ref(10); const max = ref(21); const nowVal = ref(0); const timer = ref<number | null>(null); const refCharts = ref<HTMLElement | null>(null); const state = reactive({ randomMap: new Map(), chartDom: null as HTMLElement | null, myChart: null as any, option: null as EChartsOption | null, yAxisData: [] as string[], seriesData: [] as number[], divisionData: { int: 0, yu: 0, }, }); const randomList = reactive({ value: [{ label: 0, value: 0, times: 0, divisionData: { int: 0, yu: 0 } }], }); onMounted(() => { initDom(); getOption(); startDraw(); }); onBeforeUnmount(() => { console.log('onBeforeUnmount'); }); function onGetRandomInt() { const val = getRandomInt(min.value, max.value); nowVal.value = val; const getDivision = division(val, 5); state.divisionData.int = getDivision.int; state.divisionData.yu = getDivision.yu; if (state.randomMap.has(val)) { let currentNum = state.randomMap.get(val); state.randomMap.set(val, currentNum + 1); } else { state.randomMap.set(val, 1); } let sum = 0; // eslint-disable-next-line @typescript-eslint/no-unused-vars for (const [key, value] of state.randomMap) { sum += value; } let arr = [] as any[]; for (const [key, value] of state.randomMap) { let item = {} as any; const itemGetDivision = division(value, 5); item.label = key; item.times = value; // 次数 item.value = Number(((value / sum) * 100).toFixed(2)); // 百分比值 item.divisionData = {}; item.divisionData.int = itemGetDivision.int; item.divisionData.yu = itemGetDivision.yu; arr.push(item); } arr.sort((a: any, b: any) => { return Number(b.times) - Number(a.times); }); let yAxisDataArr = [] as string[]; let seriesData = [] as number[]; arr.map((item: any) => { yAxisDataArr.push(String(item.label)); seriesData.push(item.times); }); state.yAxisData = yAxisDataArr; state.seriesData = seriesData; nextTick(() => { getOption(); startDraw(); randomList.value = arr; }); if (timer.value) { onClearTimeout(); } timer.value = window.setTimeout(() => { onGetRandomInt(); }, 2000); } function onReset() { onClearTimeout(); randomList.value = []; state.randomMap = new Map(); state.yAxisData = []; state.seriesData = []; nowVal.value = 0; state.divisionData.int = 0; state.divisionData.yu = 0; getOption(); startDraw(); } function onClearTimeout() { if (timer.value) { window.clearTimeout(timer.value); timer.value = null; } } function initDom() { state.chartDom = refCharts.value as HTMLElement; state.myChart = echarts.init(state.chartDom); } function getOption() { state.option = { grid: { top: 50, bottom: 50, left: 50, right: 50, }, xAxis: { max: 'dataMax', }, yAxis: { type: 'category', data: state.yAxisData, inverse: true, animationDuration: 300, animationDurationUpdate: 300, // max: 2, // only the largest 3 bars will be displayed }, series: [ { realtimeSort: true, type: 'bar', data: state.seriesData, label: { show: true, position: 'right', formatter: (val) => { return val.value + '次'; }, valueAnimation: true, }, itemStyle: { color: '#78c0a8', }, barWidth: 30, }, ], legend: { show: false, }, animationDuration: 0, animationDurationUpdate: 2000, animationEasing: 'linear', animationEasingUpdate: 'linear', }; } function startDraw() { state.option && state.myChart.setOption(state.option); } // 取整 取余 function division(n: number, m: number) { const yu = n % m; const int = parseInt(String(n / m)); return { yu, int, }; } </script> <template> <div class="sty-array-out-of-order"> <div class="btns"> <q-btn :label="`获取随机整数:${min}~${max}`" color="primary" @click="onGetRandomInt" ></q-btn> <q-btn label="重置" color="primary" @click="onReset"></q-btn> <q-btn label="暂停" color="primary" @click="onClearTimeout"></q-btn> <q-badge outline color="primary"> {{ nowVal }} </q-badge> </div> <div class="content"> <div class="sty-slider"> <div class="slider-item" v-for="i in randomList.value" :key="i.label"> <div class="sty-chip"> <q-chip square color="primary" text-color="white"> {{ i.label }} </q-chip> </div> <q-linear-progress size="25px" :value="i.value / 100" rounded color="primary" > <div class="absolute-full flex flex-center"> <q-badge color="white" text-color="primary" :label="i.value + '%'" /> </div> </q-linear-progress> </div> <q-separator /> <div class="steping"> <div class="step-item" v-for="i in randomList.value" :key="i.label"> <div> <q-chip square color="primary" text-color="white"> {{ i.label }} </q-chip> </div> <div class="zheng-item"> <div class="zheng-box step5" v-for="m in i.divisionData.int" :key="m" ></div> <div class="zheng-box" :class="`step${i.divisionData.yu}`"></div> </div> </div> </div> <!-- <div class="text"> <div class="zheng-box step5" v-for="i in state.divisionData.int" :key="i" ></div> <div class="zheng-box" :class="`step${state.divisionData.yu}`"></div> </div> --> </div> <div class="sty-chart"><div ref="refCharts" class="mychart"></div></div> </div> </div> </template> <style lang="scss" scoped> .sty-array-out-of-order { .btns { > button { margin-right: $padding-md; } } .content { display: grid; grid-template-columns: repeat(2, 1fr); } .sty-slider { margin-top: $padding-xl; } .slider-item { display: flex; flex-direction: row; flex-wrap: nowrap; justify-content: space-between; align-items: center; margin-bottom: $padding-lg; .sty-chip { margin-right: $padding-md; } } .sty-chart { .mychart { width: 100%; height: 650px; } } } .steping { // border: 1px solid red; display: flex; flex-direction: row; flex-wrap: nowrap; align-items: flex-start; } .step-item { display: flex; flex-direction: column; flex-wrap: nowrap; justify-content: center; align-items: center; } .zheng-item { .zheng-box { width: 25px; height: 25px; position: relative; background-size: 100% 100%; margin-bottom: 10px; } .step1 { background-image: url('./icons/zheng-1.svg'); } .step2 { background-image: url('./icons/zheng-2.svg'); } .step3 { background-image: url('./icons/zheng-3.svg'); } .step4 { background-image: url('./icons/zheng-4.svg'); } .step5 { background-image: url('./icons/zheng-5.svg'); } } </style>