数据可视化大屏(html + js + css)
数据可视化大屏
作为大数据的学生,每次想实现前端数据可视化大屏就头疼,不会前端就很烦,所以这次特定不断调教AI,再加上自己不断的改改改,终于花了一个下午改成了一个还过得去的可视化大屏,所以直接把源码分享在这里了,但是要自己导入echarts组件
index.html页面
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>电商数据可视化大屏</title>
<script src="./StyleUtils/js/utils/echarts.min.js"></script>
<script src="./StyleUtils/map/china.js"></script>
<script src="./StyleUtils/js/utils/jQuery.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="decoration decoration-1"></div>
<div class="decoration decoration-2"></div>
<div class="grid-line"></div>
<div class="dashboard">
<div class="header">
<h1>电商数据智能分析平台</h1>
<div id="timeDisplay"></div>
</div>
<!-- 第二行 -->
<div class="card">
<div class="card-title">
<i>?</i> 商品销售排行
</div>
<div class="chart-container" id="barChart1"></div>
</div>
<div class="card">
<div class="card-title">
<i>?</i> 核心数据指标
</div>
<div class="stats-container">
<div class="stat-card">
<h3>今日销售额</h3>
<div class="stat-value">¥ 1,248,560</div>
<div class="stat-trend trend-up">↑ 12.5% 较昨日</div>
</div>
<!-- <div class="stat-card">-->
<!-- <h3>订单完成量</h3>-->
<!-- <div class="stat-value">24,856</div>-->
<!-- <div class="stat-trend trend-up">↑ 8.3% 较昨日</div>-->
<!-- </div>-->
<!-- <div class="stat-card">-->
<!-- <h3>用户访问量</h3>-->
<!-- <div class="stat-value">186,423</div>-->
<!-- <div class="stat-trend trend-down">↓ 3.2% 较昨日</div>-->
<!-- </div>-->
<!-- <div class="stat-card">-->
<!-- <h3>转化率</h3>-->
<!-- <div class="stat-value">13.4%</div>-->
<!-- <div class="stat-trend trend-up">↑ 1.7% 较昨日</div>-->
<!-- </div>-->
</div>
</div>
<div class="card">
<div class="card-title">
<i>?</i> 品类销售占比
</div>
<div class="chart-container" id="barChart2"></div>
</div>
<!-- 第三行 -->
<div class="card">
<div class="card-title">
<i>?</i> 销售趋势分析
</div>
<div class="chart-container" id="lineChart1"></div>
</div>
<div class="card map-container">
<div class="card-title">
<i>?️</i> 全国销售热力图
</div>
<div class="chart-container" id="mapChart"></div>
</div>
<div class="card">
<div class="card-title">
<i>?</i> 用户活跃趋势
</div>
<div class="chart-container" id="lineChart2"></div>
</div>
<!-- 第四行 -->
<div class="card">
<div class="card-title">
<i>?</i> 用户年龄分布
</div>
<div class="chart-container" id="pieChart1"></div>
</div>
<div class="card">
<div class="card-title">
<i>?</i> 支付方式占比
</div>
<div class="chart-container" id="pieChart2"></div>
</div>
<div class="footer">
<p>数据更新时间: 2023年11月15日 14:28:35 | © 2023 电商数据平台 版权所有</p>
</div>
</div>
<script src="style.js"></script>
</body>
</html>
index.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Microsoft YaHei', sans-serif;
}
body {
background: linear-gradient(135deg, #0f172a, #1e293b);
color: #e2e8f0;
min-height: 100vh;
padding: 20px;
overflow-x: hidden;
}
.dashboard {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto;
gap: 20px;
max-width: 1920px;
margin: 0 auto;
}
.header {
grid-column: 1 / span 3;
background: rgba(15, 23, 42, 0.8);
border-radius: 16px;
padding: 20px;
text-align: center;
border: 1px solid rgba(100, 116, 139, 0.3);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.4);
backdrop-filter: blur(10px);
margin-bottom: 20px;
}
.header h1 {
font-size: 2.8rem;
margin-bottom: 10px;
background: linear-gradient(90deg, #38bdf8, #818cf8);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
letter-spacing: 2px;
}
.header p {
font-size: 1.2rem;
color: #94a3b8;
max-width: 800px;
margin: 0 auto;
}
.card {
background: rgba(15, 23, 42, 0.7);
border-radius: 16px;
border: 1px solid rgba(100, 116, 139, 0.3);
padding: 20px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
transition: transform 0.3s ease, box-shadow 0.3s ease;
height: 100%;
display: flex;
flex-direction: column;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
border-color: rgba(56, 189, 248, 0.5);
}
.card-title {
font-size: 1.3rem;
margin-bottom: 15px;
color: #38bdf8;
display: flex;
align-items: center;
gap: 10px;
}
.card-title i {
font-size: 1.5rem;
}
.chart-container {
flex: 1;
min-height: 300px;
}
.stats-container {
display: grid;
grid-template-columns: 1fr;
gap: 15px;
}
.stat-card {
background: rgba(30, 41, 59, 0.6);
border-radius: 12px;
padding: 15px;
display: flex;
flex-direction: column;
justify-content: center;
border: 1px solid rgba(100, 116, 139, 0.2);
}
.stat-card h3 {
font-size: 1rem;
color: #94a3b8;
margin-bottom: 8px;
}
.stat-value {
font-size: 2rem;
font-weight: bold;
color: #38bdf8;
}
.stat-trend {
display: flex;
align-items: center;
font-size: 0.9rem;
margin-top: 5px;
}
.trend-up {
color: #10b981;
}
.trend-down {
color: #ef4444;
}
.map-container {
grid-row: 3 / span 2;
grid-column: 2;
}
.footer {
grid-column: 1 / span 3;
text-align: center;
padding: 20px;
font-size: 0.9rem;
color: #64748b;
margin-top: 20px;
}
/* 响应式调整 */
@media (max-width: 1200px) {
.dashboard {
grid-template-columns: 1fr 1fr;
}
.header, .footer {
grid-column: 1 / span 2;
}
.map-container {
grid-row: auto;
grid-column: 1 / span 2;
}
}
@media (max-width: 768px) {
.dashboard {
grid-template-columns: 1fr;
}
.header, .footer {
grid-column: 1;
}
.map-container {
grid-column: 1;
}
}
/* 装饰元素 */
.decoration {
position: absolute;
z-index: -1;
opacity: 0.1;
}
.decoration-1 {
width: 400px;
height: 400px;
border-radius: 50%;
background: linear-gradient(135deg, #38bdf8, #818cf8);
top: -100px;
right: -100px;
}
.decoration-2 {
width: 300px;
height: 300px;
border-radius: 50%;
background: linear-gradient(135deg, #8b5cf6, #ec4899);
bottom: -100px;
left: -100px;
}
.grid-line {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background:
linear-gradient(to right, rgba(100, 116, 139, 0.05) 1px, transparent 1px),
linear-gradient(to bottom, rgba(100, 116, 139, 0.05) 1px, transparent 1px);
background-size: 40px 40px;
z-index: -1;
}
index.js(我自己加了一个后端获取的通用方法,到时根据自己需求稍微改改代码就可以了,数据都是静态数据,后续有时间我就更新怎么从后端获取数据,然后进行数据显示)
// 通用数据获取
async function fetchData(url, params = {}) {
try {
const response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error(error);
return null;
}
}
// 初始化所有图表
document.addEventListener('DOMContentLoaded', function() {
// 更新时间显示
function updateTime() {
const now = new Date();
const timeDisplay = document.getElementById('timeDisplay');
const options = {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
};
timeDisplay.textContent = now.toLocaleDateString('zh-CN', options);
}
// 初始化时间并设置定时器
updateTime();
setInterval(updateTime, 1000);
function initOption() {
bar1()
bar2()
line1()
line2()
pie1()
pie2()
map()
}
// 商品销售排行
function bar1() {
const barChart1 = echarts.init(document.getElementById('barChart1'));
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['智能手机', '笔记本电脑', '智能手表', '蓝牙耳机', '平板电脑', '相机', '游戏主机'],
axisLine: {
lineStyle: {
color: '#64748b'
}
}
},
yAxis: {
type: 'value',
name: '销售额 (万元)',
nameTextStyle: {
color: '#94a3b8'
},
axisLine: {
lineStyle: {
color: '#64748b'
}
},
splitLine: {
lineStyle: {
color: 'rgba(100, 116, 139, 0.2)'
}
}
},
series: [{
name: '销售额',
type: 'bar',
data: [125, 98, 76, 65, 58, 42, 35],
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#38bdf8' },
{ offset: 1, color: '#0ea5e9' }
])
},
label: {
show: true,
position: 'top',
color: '#e2e8f0'
}
}]
};
barChart1.setOption(option);
}
// 品类销售占比
function bar2() {
const barChart2 = echarts.init(document.getElementById('barChart2'));
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'value',
axisLine: {
lineStyle: {
color: '#64748b'
}
},
splitLine: {
lineStyle: {
color: 'rgba(100, 116, 139, 0.2)'
}
}
},
yAxis: {
type: 'category',
data: ['数码电子', '家用电器', '服装鞋帽', '美妆护肤', '食品生鲜', '家居用品', '图书文具'],
axisLine: {
lineStyle: {
color: '#64748b'
}
}
},
series: [{
name: '占比',
type: 'bar',
data: [35, 28, 22, 18, 15, 12, 8],
itemStyle: {
color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [
{ offset: 0, color: '#818cf8' },
{ offset: 1, color: '#6366f1' }
])
},
label: {
show: true,
position: 'right',
color: '#e2e8f0'
}
}]
}
barChart2.setOption(option);
}
// 销售趋势分析
function line1() {
const lineChart1 = echarts.init(document.getElementById('lineChart1'));
const option = {
tooltip: {
trigger: 'axis'
},
legend: {
data: ['销售额', '订单量'],
textStyle: {
color: '#94a3b8'
},
right: 10,
top: 0
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '20%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['11/09', '11/10', '11/11', '11/12', '11/13', '11/14', '11/15'],
axisLine: {
lineStyle: {
color: '#64748b'
}
}
},
yAxis: {
type: 'value',
name: '销售额 (万元)',
nameTextStyle: {
color: '#94a3b8'
},
axisLine: {
lineStyle: {
color: '#64748b'
}
},
splitLine: {
lineStyle: {
color: 'rgba(100, 116, 139, 0.2)'
}
}
},
series: [
{
name: '销售额',
type: 'line',
data: [820, 932, 1560, 1434, 1290, 1030, 1248],
smooth: true,
lineStyle: {
width: 3,
color: '#38bdf8'
},
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#38bdf8'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(56, 189, 248, 0.5)' },
{ offset: 1, color: 'rgba(56, 189, 248, 0.1)' }
])
}
},
{
name: '订单量',
type: 'line',
yAxisIndex: 0,
data: [18.2, 19.5, 32.4, 28.6, 25.3, 20.8, 24.8],
smooth: true,
lineStyle: {
width: 3,
color: '#8b5cf6'
},
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#8b5cf6'
}
}
]
}
lineChart1.setOption(option);
}
// 用户活跃趋势
function line2() {
const lineChart2 = echarts.init(document.getElementById('lineChart2'));
const option = {
tooltip: {
trigger: 'axis'
},
legend: {
data: ['活跃用户', '新增用户'],
textStyle: {
color: '#94a3b8'
},
right: 10,
top: 0
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '20%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
axisLine: {
lineStyle: {
color: '#64748b'
}
}
},
yAxis: {
type: 'value',
name: '用户量 (万)',
nameTextStyle: {
color: '#94a3b8'
},
axisLine: {
lineStyle: {
color: '#64748b'
}
},
splitLine: {
lineStyle: {
color: 'rgba(100, 116, 139, 0.2)'
}
}
},
series: [
{
name: '活跃用户',
type: 'line',
data: [132, 145, 158, 142, 168, 185, 162],
smooth: true,
lineStyle: {
width: 3,
color: '#10b981'
},
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#10b981'
}
},
{
name: '新增用户',
type: 'line',
data: [28, 32, 36, 31, 35, 42, 38],
smooth: true,
lineStyle: {
width: 3,
color: '#f59e0b'
},
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#f59e0b'
}
}
]
}
lineChart2.setOption(option);
}
// 用户年龄分布
function pie1() {
const pieChart1 = echarts.init(document.getElementById('pieChart1'));
const option = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
right: 10,
top: 'center',
textStyle: {
color: '#94a3b8'
}
},
series: [
{
name: '年龄分布',
type: 'pie',
radius: ['40%', '70%'],
center: ['40%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#0f172a',
borderWidth: 2
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '18',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{ value: 28, name: '18岁以下', itemStyle: { color: '#38bdf8' } },
{ value: 145, name: '18-25岁', itemStyle: { color: '#818cf8' } },
{ value: 235, name: '26-35岁', itemStyle: { color: '#8b5cf6' } },
{ value: 187, name: '36-45岁', itemStyle: { color: '#ec4899' } },
{ value: 95, name: '46-60岁', itemStyle: { color: '#f59e0b' } },
{ value: 42, name: '60岁以上', itemStyle: { color: '#10b981' } }
]
}
]
}
pieChart1.setOption(option);
}
// 支付方式占比
function pie2() {
const pieChart2 = echarts.init(document.getElementById('pieChart2'));
const option = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
series: [
{
name: '支付方式',
type: 'pie',
radius: '70%',
center: ['50%', '50%'],
roseType: 'radius',
itemStyle: {
borderRadius: 5,
borderColor: '#0f172a',
borderWidth: 2
},
label: {
color: '#e2e8f0'
},
data: [
{ value: 45, name: '支付宝', itemStyle: { color: '#1677ff' } },
{ value: 30, name: '微信支付', itemStyle: { color: '#07c160' } },
{ value: 15, name: '银行卡', itemStyle: { color: '#0ea5e9' } },
{ value: 8, name: '云闪付', itemStyle: { color: '#eb2f96' } },
{ value: 2, name: '其他方式', itemStyle: { color: '#f59e0b' } }
]
}
]
}
pieChart2.setOption(option);
}
// 随机数
function randomData() {
return Math.round(Math.random() * 500);
}
// 全国销售热力图
function map() {
const mapChart = echarts.init(document.getElementById('mapChart'));
const mydata = [
{name: '北京',value: randomData() },{name: '天津',value: randomData() },
{name: '上海',value: randomData() },{name: '重庆',value: randomData() },
{name: '河北',value: randomData() },{name: '河南',value: randomData() },
{name: '云南',value: randomData() },{name: '辽宁',value: randomData() },
{name: '黑龙江',value: randomData() },{name: '湖南',value: randomData()},
{name: '安徽',value: randomData() },{name: '山东',value: randomData() },
{name: '新疆',value: randomData() },{name: '江苏',value: randomData() },
{name: '浙江',value: randomData() },{name: '江西',value: randomData() },
{name: '湖北',value: randomData() },{name: '广西',value: randomData() },
{name: '甘肃',value: randomData() },{name: '山西',value: randomData() },
{name: '内蒙古',value: randomData() },{name: '陕西',value: randomData()},
{name: '吉林',value: randomData() },{name: '福建',value: randomData() },
{name: '贵州',value: randomData() },{name: '广东',value: randomData() },
{name: '青海',value: randomData() },{name: '西藏',value: randomData() },
{name: '四川',value: randomData() },{name: '宁夏',value: randomData() },
{name: '海南',value: randomData() },{name: '台湾',value: randomData() },
{name: '香港',value: randomData() },{name: '澳门',value: randomData() }
];
const option = {
//backgroundColor: '#FFFFFF',
// 标题
title: {
text: '各省份的总成交量对比',
textStyle:{color:'#fff'},
//subtext: '纯属虚构',
x:'center',
show: true
},
// 提示框
tooltip : {
trigger: 'item'
},
visualMap: {
show : true,
x: 'left',
y: 'bottom',
//layoutCenter:['30%','30%'],
splitList: [
{start: 500, end:600},{start: 400, end: 500},
{start: 300, end: 400},{start: 200, end: 300},
{start: 100, end: 200},{start: 0, end: 100},
],
// color: ['#ff0', '#ffff00', '#0E94EB','#6FBCF0', '#F0F06F', '#00CC00']
color:['#5bc2e7', '#6980c5', '#70dfdf', '#f7f1ee', '#3390FF']
},
series: [{
name: '各省份的总成交量对比',
type: 'map',
mapType: 'china',
label: {
normal: {
show: false
},
emphasis: {
show: false
}
},
data:mydata
}]
};
mapChart.setOption(option);
}
initOption()
// 响应式调整
window.addEventListener('resize', function() {
bar1.resize();
bar2.resize();
line1.resize();
mapChart.resize();
lineChart2.resize();
pieChart1.resize();
pieChart2.resize();
});
});
效果图
都能完美实现,没实现成功的看看是否组件导入没,注意啊,这不是vue项目,是纯种的html,嘻嘻。最后实现的效果可能页面太大了,最好都是一页将所有显示出来,所以会前端的大佬可以自己修改,不会前端那就只能让AI改了(我就是)