大屏可视化效果实现记录
适配及响应式处理
效果实现
Echarts线图线条渐变色及区域渐变
- 效果图
- 关注点
- 线条颜色渐变
- 线条含有阴影
- 区域填充色渐变
- 配置项
series:[{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
smooth: false,
lineStyle: {
normal: {
// 1. 设置线条渐变色
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{
offset: 0,
color: '#FDFDFF',
},
{
offset: 0.3,
color: '#6EA4F8',
},
{
offset: 0.6,
color: '#7DA0E0',
}, {
offset: 1,
color: '#679BF0',
},
]),
width: 3,
// 2. 设置线条阴影
shadowColor: '#2E4F84',
shadowOffsetY: 15,
shadowOffsetX: 5,
shadowBlur: 3,
},
},
// 3. 设置区域填充渐变:渐变色设置文档
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: 'rgba(36,173,254, 0.5)',
}, {
offset: 1,
color: 'rgba(52,112,252, 0.1)',
},
],
},
},
}]
Echarts外环饼图
- 效果图
- 关注点
- 内圈含有间隔数据
- 外圈效果
- 配置项
// 数据处理
// 间隔空白数据
const gapData = {
name: '',
value: 20,
itemStyle: {
color: 'transparent', // 颜色设置为透明数据
},
};
// 计算饼图渲染数据
const seriesData = [];
[
{ value: 1048, name: 'Search Engine' },
{ value: 735, name: 'Direct' },
{ value: 580, name: 'Email' },
{ value: 484, name: 'Union Ads' },
{ value: 300, name: 'Video Ads' }
].forEach((item) => {
seriesData.push(item);
seriesData.push(gapData);
});
// 图表配置项
series: [
// 内圆环配置项
{
data: seriesData,
roundCap: true,
center: ['50%', '50%'],
radius: ['50%', '60%'],
label: {
show: false,
position: 'center',
},
},
// 外圆环配置项
{
type: 'pie',
name: '旋转圆',
silent: true,
center: ['50%', '50%'],
radius: ['70%', '69%'],
hoverAnimation: false,
startAngle: 50,
// Notes:这里的数据根据要展示的外环段数及长短自定义设置
data:[120, 40, 120, 40, 120, 40].map((item, index) => ({
value: item,
name: '',
itemStyle: {
color: index % 2 === 0 ? '#5999E1' : 'transparent',
shadowBlur: 20,
shadowColor: '#86C6FD',
},
})),
label: {
normal: {
show: false,
},
},
labelLine: {
normal: {
show: false,
},
},
}
],
Echarts 渐变色柱状图
- 效果图
- 关注点
- 柱体颜色渐变
- 配置项
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar',
// 设置柱体颜色渐变
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 1,
color: '#20517E',
opacity: 0.85,
},
{
offset: 0,
color: '#3FC0F7',
opacity: 0.79,
},
]),
},
},
label: {
show: true,
color:'#3FC0F7',
fontSize: 12,
position: 'outside',
},
}
]
Echarts含图片标签渐变色柱状图
- 效果图
- 关注项
- 渐变色柱体
- 高亮结尾
- 数据标签含背景图
- 配置项
option = {
backgroundColor:'#17243A',
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'value',
boundaryGap: [0, 0.01]
},
yAxis: [
{
inverse: true,
axisLabel: {
color: '#ADCBE9',
fontSize: 20,
formatter: (value) => {
if (value.length < 8) {
return value;
}
return `${value.substring(0, 8)}...`;
},
},
axisLine: {
lineStyle: {
color: 'transparent',
},
},
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
}, {
inverse: true,
axisTick: 'none',
axisLine: 'none',
axisLabel: {
show: true,
fontSize: 20,
fontWeight: 'bold',
color: '#BFD1E3',
padding: [5, 12, 5, 12],
backgroundColor: {
image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAWCAYAAAA/45nkAAAACXBIWXMAAAsTAAALEwEAmpwYAAABAElEQVRoge3ZwQoBURTG8XOvKzGzmnQ3SpKJrMZb2HsQL+MRLCkb5RHsbNVspGwkRYamplipaSiUOodzZnl/d/FvZvPVqP5geoXMs18ve0l8ibLnfq1SDlebXfZc7LWZQtHxqq1x1g0AwDZcdKmG/4sl8SW6v+e7HfJ2qCnEcTaNHcDdNAAA1TgOlqv77TnVuH+3ODpO9LuXxb5vSXw+PXwAKnFcTH9yWez7JjMU2WSGYs9Q7ADuprEDuJvMUGSTGYpsMkORTWYooplCydW2EYwoxnEwr9ocaVDKpRjHxZ6uICpxHExmKLIZAADrd2bpwzD175Jq+C+abQRjUMpJ+w1co8ZyUwNCuQAAAABJRU5ErkJggg==',
},
},
data: [120, 200, 150, 80, 70, 110, 130],
},
],
series: [
{
type: 'pictorialBar',
symbol: 'image://data:image/png;base64,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',
symbolOffset: [20, -5],
symbolSize: [40, 40],
symbolPosition: 'end',
z: 12,
data: [120, 200, 150, 80, 70, 110, 130],
}, {
name: '',
type: 'bar',
showBackground: true,
yAxisIndex: 0,
barWidth: 7,
barBorderRadius: 10,
data: [120, 200, 150, 80, 70, 110, 130].map((value, index) => ({
value,
itemStyle: {
normal: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [
{
offset: 0,
color: '#2F3E56',
},
{
offset: 1,
color:'#7BB1EE',
},
],
},
},
},
})),
},
]
};
Echarts立体柱状图
- 效果图
- 关注点
- 三面立体
- 柱体渐变
- 配置项
// 自定义图形
// 绘制左侧面
export const CubeLeft = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0,
},
buildPath (ctx, shape) {
const xAxisPoint = shape.xAxisPoint;
const c0 = [shape.x, shape.y];
const c1 = [shape.x - offsetX, shape.y - offsetY];
const c2 = [xAxisPoint[0] - offsetX, xAxisPoint[1] - offsetY];
const c3 = [xAxisPoint[0], xAxisPoint[1]];
ctx.moveTo(c0[0], c0[1]).lineTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1])
.closePath();
},
});
// 绘制右侧面
export const CubeRight = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0,
},
buildPath (ctx, shape) {
const xAxisPoint = shape.xAxisPoint;
const c1 = [shape.x, shape.y];
const c2 = [xAxisPoint[0], xAxisPoint[1]];
const c3 = [xAxisPoint[0] + offsetX, xAxisPoint[1] - offsetY];
const c4 = [shape.x + offsetX, shape.y - offsetY];
ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1])
.closePath();
},
});
// 绘制顶面
export const CubeTop = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0,
},
buildPath (ctx, shape) {
const c1 = [shape.x, shape.y];
const c2 = [shape.x + offsetX, shape.y - offsetY]; // 右点
const c3 = [shape.x, shape.y - offsetX];
const c4 = [shape.x - offsetX, shape.y - offsetY];
ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1])
.closePath();
},
});function getRenderItem(param, type) {
const colorList = ['#66C9F2', '#80D1CD', '#9BD977'];
const color = colorList[param.dataIndex % 3];
const rgba = color16ToRGBA(color, type === 'top' ? 0.6 : 0.01);
return {
fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 1,
color: rgba,
},
{
offset: 0,
color,
},
]),
};
}// 图表配置项
config = {
xAxis: {
axisLine: {
lineStyle: {
color: 'transparent',
},
},
axisLabel: {
color: '#B1CBD8',
fontSize: 20,
},
},
yAxis: {
show: false,
splitLine: {
show: false,
},
},
series:[
{
type: 'custom',
// 使用自定义的图形进行绘制
renderItem: (params, api) => {
const location = api.coord([api.value(0), api.value(1)]);
return {
type: 'group',
children: [
{
type: 'CubeLeft', // 绘制左侧面
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: api.coord([api.value(0), 0]),
},
style: {
...getRenderItem(params),
},
},
{
type: 'CubeRight', // 绘制右侧面
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: api.coord([api.value(0), 0]),
},
style: {
...getRenderItem(params),
},
},
{
type: 'CubeTop', // 绘制顶层
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: api.coord([api.value(0), 0]),
},
style: {
...getRenderItem(params, 'top'),
},
},
],
};
},
data: [120, 200, 150, 80, 70, 110, 130],
},
{
type: 'bar',
label: {
normal: {
show: true,
position: 'top',
formatter: e => `${e.value}%`,
fontSize: 15,
color: '#fff',
offset: [0, -15],
},
},
itemStyle: {
color: 'transparent',
},
tooltip: {},
data: [120, 200, 150, 80, 70, 110, 130],
},
]
}
CSS旋转圆动画效果
- 效果图
- 关注点
- 背景图渐变
- 旋转动画
- 实现
<div class="value">
<span>{{ item.value }}span>
<span class="unit">%span>
div>
/** 定义旋转动画 **/
@keyframes rotate {
100% {
transform: rotate(360deg);
}
}
.value {
width: 9vh;
height: 9vh;
line-height: 9vh;
text-align: center;
position: relative;
margin: auto;
border-radius: 50%;
/** 设置元素背景径向渐变色 **/
background: radial-gradient(50% 50% at 50% 50%, rgba(12, 27, 48, 0.1) 0%, rgba(12, 27, 48, 0.1) 49%, rgba(116, 217, 229, 0.1) 98%);
text-align: center;
.unit {
font-size: 1.4vh;
position: absolute;
margin-top: 3px;
margin-left: 3px;
}
/** 添加外环元素 **/
&::before,
&::after {
content: "";
position: absolute;
top: -1.5vh;
left: -1.5vh;
bottom: -1.5vh;
right: -1.5vh;
border-radius: 50%;
border-top: 3px solid #58A7B4;
/** 为外环元素添加旋转动画 **/
animation: rotate 6s infinite linear;
}
/** 第二个半圆添加动画延迟3S,使两个动画可以交替执行 **/
&::after {
animation-delay: 3s;
}
}
CSS元素浮动漂浮效果
- 效果图
- 实现
/** 定义浮动动画 **/
@keyframes float {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-20px);
}
100% {
transform: translateY(0);
}
}
/** 为元素整体添加动画 **/
.indicator{
...其他样式项
animation: float 3s infinite ease-in-out;
/** 往后每个元素的动画执行延迟2s,保证不同的漂浮幅度 **/
&.indicator2{
animation-delay: 2s;
}
&.indicator3{
animation-delay: 4s;
}
&.indicator4{
animation-delay: 6s;
}
}
字体渐变色
- 效果
- 关注点
- 背景绘制区域:background-clip
- 实现
span {
/** 设置字体的背景色为径向渐变色 **/
background: linear-gradient(180deg, #F5F5F5 0%, #7EB8E6 100%);
/** 将背景作用区域更新为文本,背景被裁剪为文字的形状 **/
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
/** 文字本身设置为透明色 **/
color: transparent;
}
其他
动态渲染大屏模块
- 背景
一般大屏页面会显示多个小模块,在不同的场景下分别配置显示哪几个。当前由接口提供一组要渲染的模块值,需要根据接口动态设置要渲染的内容
- 实现方式
由Vue component动态组件进行渲染
- 从接口获取一组模块名称:comList
- 对comList进行遍历,使用component :is 进行匹配渲染
- 注意组件的name名称,使用:is匹配时,需要字段值于之一致
<template v-for="name in comList">
<component :is="name" :key="name"/>
template>
定时器更新图表数据
- 背景
所有图表数据量较多,不宜一次性展示全部,而是分组进行循环展示。即每次展示5条数据,间隔一定时间后切换至下5条数据,以此循环。
- 实现方式
在顶层App.vue组件中,开启一个定时器,并使用
moduleTimerCount
字段记录当前的组别数,按时间间隔更新该字段。并在子组件中监听该字段,该字段变化时计算当前子组件需要显示的数据条数,并更细图表数据。- 声明
moduleTimerCount
变量
data(){
return {
moduleTimerCount:0
}
}- 开启一个定时器
- 声明
使用 setTimeout
模拟 setInterval
定时器(相比于setInterval,setTimeout每次执行完当前次任务后才会执行下一次任务,不存在任务堆积问题,每次执行完后自行清理、独立调用,内存泄露的风险较低)。
```JavaScript
function openModuleRefresh(delay) {
const execute = () => {
this.moduleTimerCount += 1;
if (moduleRefreshTime) {
clearTimeout(moduleRefreshTime);
}
moduleRefreshTime = setTimeout(execute, delay * 1000);
};
setTimeout(execute, delay * 1000); // 首次延迟执行
},
```
3. 子组件监听字段变化
```JavaScript
watch: {
moduleTimerCount(value) {
if (dataList) {
// 当前接口数据的数据长度
const dataLength = dataList.length;
// 每5个分一组,计算组别数
const totalGr0up = Math.ceil(dataLength / 5);
// 计算当前组别数,使用 moduleTimerCount 值对组别数取余,保证获取的当前组别不会超过总组别数
this.chartGr0upIndex = value % totalGr0up;
// 计算当前的数据,由组别数获取当前组的数据索引
const startIndex = this.chartGr0upIndex * 5;
let endIndex = (this.chartGr0upIndex + 1) * 5;
if (endIndex >= echartsData.data.length) {
endIndex = echartsData.data.length;
}
// 根据索引截取数据
const renderChartData = echartsData.slice(startIndex, endIndex);
}
},
},
```
作者:云小遥
来源:juejin.cn/post/7439207153938317339
来源:juejin.cn/post/7439207153938317339