应对现在数据可视化的趋势,越来越多企业需要在很多场景(营销数据,生产数据,用户数据)下使用,可视化图表来展示体现数据,让数据更加直观,数据特点更加突出。
一、使用技术
完成该项目需要具备以下知识:
-
div + css 布局
-
flex 布局(分为三列)
-
Less
-
原生js + jquery 使用
-
rem适配
-
echarts基础
基于flexible.js + rem 智能大屏适配
页面分为顶部的header和下面的主体区域。主体区域通过flex布局分为左中右三部分

新建项目目录为my-bigscreen文件夹,该文件夹下面新建css、images、font、js四个文件夹,新建index.html文件,初始内容如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>数据可视化</title> </head> <body> </body> </html>
使用vscode打开项目,如下所示

css目录下新建index.less,保存之后就会生成index.css
将css引入到index.html中,输入link:css就会快速生成link标签
<link rel="stylesheet" href="css/index.css">
css初始化
即在index.less文件中输入以下内容:
// css初始化 * { margin: 0; padding: 0; box-sizing: border-box; }
在body标签内输入123,安装preview on web server插件,然后在index.html中点击鼠标右键,选择vscode-preview-server:Launch on browser,即可浏览器中预览index.html文件

发现能看到123,说明样式引入成功。
二、
(function flexible(window, document) { var docEl = document.documentElement; var dpr = window.devicePixelRatio || 1; // adjust body font size function setBodyFontSize() { if (document.body) { document.body.style.fontSize = 12 * dpr + "px"; } else { document.addEventListener("DOMContentLoaded", setBodyFontSize); } } setBodyFontSize(); // set 1rem = viewWidth / 10 function setRemUnit() { var rem = docEl.clientWidth / 24; docEl.style.fontSize = rem + "px"; } setRemUnit(); // reset rem unit on page resize window.addEventListener("resize", setRemUnit); window.addEventListener("pageshow", function(e) { if (e.persisted) { setRemUnit(); } }); // detect 0.5px supports if (dpr >= 2) { var fakeBody = document.createElement("body"); var testElement = document.createElement("div"); testElement.style.border = ".5px solid transparent"; fakeBody.appendChild(testElement); docEl.appendChild(fakeBody); if (testElement.offsetHeight === 1) { docEl.classList.add("hairlines"); } docEl.removeChild(fakeBody); } })(window, document);
<body>
123
<script src="js/flexible.js"></script>
</body>
保存,如何flexible.js引入成功呢?我们可以在页面审查元素,如果html标签出现font-size,并且font-size的值根据页面尺寸的大小变化而变化,说明flexible.js引入成功。

-
-
flexible.js 把屏幕分为 24 等份
-
cssrem 插件的基准值是 80px
插件-配置按钮---配置扩展设置--Root Font Size 里面 设置。
注意:flexible.js默认将屏幕划分成10等分,代码如下:
function setRemUnit() { var rem = docEl.clientWidth / 10; docEl.style.fontSize = rem + "px"; }
我们现在将屏幕宽度划分位24等分,修改代码如下:
function setRemUnit() { var rem = docEl.clientWidth / 24; docEl.style.fontSize = rem + "px"; }
即页面的1rem为80px。
安装px to rem & rpx & vw (cssrem)插件,安装完之后,点击设置按钮,如下所示:

选择Extension Settings,将Root Font Size修改为80即可

这样会自动帮我们生成rem,现在来测试是否帮我们生成成功。
在index.html中输入.box命令就会生成class名称为box的div标签,然后在index.less文件中写样式如下:
.box{ width: 1rem; height: 1rem; background-color: pink; }
可以看到自动帮我们转为1rem,当我们输入80px时,会有提示如下:

当我们选择80px->1rem时,则会输入1rem
保存后在浏览器中查看,如下所示:

发现当页面尺寸发生变化时,div的尺寸也会相应变化。
三、
body { background: url(../images/bg.jpg); }
浏览器查看如下:

发现背景图平铺了,我们可以通过background-size值为cover设置完全满铺容器
body { /* 背景图定位 / 背景图尺寸 cover 完全铺满容器 contain 完整显示在容器内 */ background: url(../images/bg.jpg) no-repeat #000; background-size: cover; }
效果如下:

这样,背景图片设置成功。
body { /* 背景图定位 / 背景图尺寸 cover 完全铺满容器 contain 完整显示在容器内 */ background: url(../images/bg.jpg) no-repeat #000; background-size: cover; /* 行高是字体1.15倍 */ line-height: 1.15; }
四、
-
-
背景图,在容器内显示
-
缩放比例为 100%
-
h1 标题部分 白色 38像素 居中显示 行高为 80像素
-
在index.html中输入头部的盒子
<body>
<!-- 头部的盒子 -->
<header></header>
<script src="js/flexible.js"></script>
</body>
将head_bg.png放入images目录中
index.less中编写样式
header { height: 1.25rem; // background-color: pink; background: url(../images/head_bg.png) no-repeat; background-size: 100% 100%; }
用h1标签编写标题
<body>
<!-- 头部的盒子 -->
<header>
<h1>数据可视化-Echarts</h1>
</header>
<script src="js/flexible.js"></script>
</body>
编写样式
header { height: 1.25rem; // background-color: pink; background: url(../images/head_bg.png) no-repeat; background-size: 100% 100%; h1 { color: #fff; font-size: .475rem; text-align: center; line-height: 1rem; } }
效果如下:

编写时间的div,时间先写死
<body>
<!-- 头部的盒子 -->
<header>
<h1>数据可视化-Echarts</h1>
<div class="showTime">当前时间:2023年3月15日 11时22分12秒</div>
</header>
<script src="js/flexible.js"></script>
</body>
编写样式
header { position: relative; height: 1.25rem; // background-color: pink; background: url(../images/head_bg.png) no-repeat; background-size: 100% 100%; h1 { color: #fff; font-size: .475rem; text-align: center; line-height: 1rem; } .showTime { position: absolute; top: 0; right: .375rem; line-height: .9375rem; font-size: .25rem; color: rgba(255,255,255,0.7); } }
注意:子绝父相,即子为绝对定位,则父为相对定位。
效果如下:

通过js代码来生成时间
<body>
<!-- 头部的盒子 -->
<header>
<h1>数据可视化-Echarts</h1>
<div class="showTime"></div>
<script>
var t = null;
t = setTimeout(time, 1000);//開始运行
function time() {
clearTimeout(t);//清除定时器
dt = new Date();
var y = dt.getFullYear();
var mt = dt.getMonth() + 1;
var day = dt.getDate();
var h = dt.getHours();//获取时
var m = dt.getMinutes();//获取分
var s = dt.getSeconds();//获取秒
document.querySelector(".showTime").innerHTML = '当前时间:' + y + "年" + mt + "月" + day + "-" + h + "时" + m + "分" + s + "秒";
t = setTimeout(time, 1000); //设定定时器,循环运行
}
</script>
</header>
<script src="js/flexible.js"></script>
</body>
即每一秒更改一次数据,循环运行。
五、
-
需要一个上左右的10px 的内边距
index.html中编写主体区域的div,输入section.mainbox快速生成代码
<!-- 主体区域 -->
<section class="mainbox">主体区域</section>
编写样式
.mainbox { // 当宽度小于1024就不会再缩放了 min-width: 1024px; max-width: 1920px; margin: 0 auto; padding: .125rem .125rem 0; background-color: pink; }
效果如下:

index.html中输入.column*3就会生成三个class为column的div
<!-- 主体区域 -->
<section class="mainbox">
<div class="column">1</div>
<div class="column">2</div>
<div class="column">3</div>
</section>
编写样式
.mainbox { display: flex; // 当宽度小于1024就不会再缩放了 min-width: 1024px; max-width: 1920px; margin: 0 auto; padding: .125rem .125rem 0; background-color: pink; .column { flex: 3; } .column:nth-child(2) { flex: 5; } }
效果如下:

六、
-
-
1像素的 1px solid rgba(25, 186, 139, 0.17) 边框
-
有line.jpg 背景图片
-
padding为 上为 0 左右 15px 下为 40px
-
下外边距是 15px
-
利用panel 盒子 before 和after 制作上面两个角 大小为 10px 线条为 2px solid #02a6b5
-
编写一个class为panel的div
<!-- 主体区域 -->
<section class="mainbox">
<div class="column">
<div class="panel"></div>
</div>
<div class="column">2</div>
<div class="column">3</div>
</section>
编写样式
.mainbox { display: flex; // 当宽度小于1024就不会再缩放了 min-width: 1024px; max-width: 1920px; margin: 0 auto; padding: .125rem .125rem 0; // background-color: pink; .column { flex: 3; .panel { height: 3.875rem; background-color: pink; } } .column:nth-child(2) { flex: 5; } }
效果如下:

继续编写样式
.column { flex: 3; .panel { height: 3.875rem; // background-color: pink; border: .0125rem solid rgba(25,186,139,0.17); background: url(../images/line.png) rgba(255,255,255,0.04); padding: 0 .1875rem .5rem; margin-bottom: .1875rem; } }
效果如下:

编写四个角
.column { flex: 3; .panel { position: relative; height: 3.875rem; // background-color: pink; border: .0125rem solid rgba(25,186,139,0.17); background: url(../images/line.png) rgba(255,255,255,0.04); padding: 0 .1875rem .5rem; margin-bottom: .1875rem; &::before { position: absolute; top: 0; left: 0; width: .125rem; height: .125rem; border-left: 2px solid #02a6b5; border-top: 2px solid #02a6b5; content: "1"; } } }
效果如下:

同理,右上角样式编写
&::after { position: absolute; top: 0; right: 0; width: .125rem; height: .125rem; border-right: 2px solid #02a6b5; border-top: 2px solid #02a6b5; content: "1"; } }
在panel盒子中加一个div
<!-- 主体区域 -->
<section class="mainbox">
<div class="column">
<div class="panel">
<div class="panel-footer"></div>
</div>
</div>
<div class="column">2</div>
<div class="column">3</div>
</section>
编写样式
.panel-footer { position: absolute; bottom: 0; left: 0; width: 100%; &::before { position: absolute; bottom: 0; left: 0; width: .125rem; height: .125rem; border-left: 2px solid #02a6b5; border-bottom: 2px solid #02a6b5; content: ""; } &::after { position: absolute; bottom: 0; right: 0; width: .125rem; height: .125rem; border-right: 2px solid #02a6b5; border-bottom: 2px solid #02a6b5; content: ""; } }
注意:一个盒子只有一个before和一个after
效果如下:

七、
-
-
图标内容模块 chart 高度 240px
-
每个panel盒子分为上下两部分,上部为标题,下部为内容
添加标题和内容的盒子
<!-- 主体区域 -->
<section class="mainbox">
<div class="column">
<div class="panel bar">
<h2>柱形图-就业行业</h2>
<div class="chart">图表</div>
<div class="panel-footer"></div>
</div>
</div>
<div class="column">2</div>
<div class="column">3</div>
</section>
编写样式
h2 { height: .6rem; font-size: .25rem; line-height: .6rem; color: #fff; text-align: center; } .chart{ height: 3rem; background-color: pink; }
效果如下:

由于左侧的三个图样式相同,我们复制三分
<!-- 主体区域 -->
<section class="mainbox">
<div class="column">
<div class="panel bar">
<h2>柱形图-就业行业</h2>
<div class="chart">条形图</div>
<div class="panel-footer"></div>
</div>
<div class="panel line">
<h2>柱形图-就业行业</h2>
<div class="chart">折线图</div>
<div class="panel-footer"></div>
</div>
<div class="panel pie">
<h2>柱形图-就业行业</h2>
<div class="chart">饼图</div>
<div class="panel-footer"></div>
</div>
</div>
<div class="column">2</div>
<div class="column">3</div>
</section>
效果如下:

由于右侧三个图和左侧三个图样式是一样的,我们也复制一份
<!-- 主体区域 -->
<section class="mainbox">
<div class="column">
<div class="panel bar">
<h2>柱状图-就业行业</h2>
<div class="chart">柱状图</div>
<div class="panel-footer"></div>
</div>
<div class="panel line">
<h2>折线图-人员变化</h2>
<div class="chart">折线图</div>
<div class="panel-footer"></div>
</div>
<div class="panel pie">
<h2>饼形图-年龄分布</h2>
<div class="chart">饼图</div>
<div class="panel-footer"></div>
</div>
</div>
<div class="column">2</div>
<div class="column">
<div class="panel bar">
<h2>柱状图-技能掌握</h2>
<div class="chart">柱状图</div>
<div class="panel-footer"></div>
</div>
<div class="panel line">
<h2>折线图-播放量</h2>
<div class="chart">折线图</div>
<div class="panel-footer"></div>
</div>
<div class="panel pie">
<h2>饼形图-地区分布</h2>
<div class="chart">饼图</div>
<div class="panel-footer"></div>
</div>
</div>
</section>
效果如下:

八、
-
上面是no 数字模块
-
下面是map 地图模块
-
数字模块 no 有个背景颜色 rgba(101, 132, 226, 0.1); 有个15像素的内边距
-
注意中间列 column 有个 左右 10px 下 15px 的外边距
-
no 模块里面上下划分 上面是数字(no-hd) 下面 是 相关文字说明(no-bd)
-
no-hd 数字模块 有一个边框 1px solid rgba(25, 186, 139, 0.17)
-
no-hd 数字模块 里面分为两个小li 每个小li高度为 80px 文字大小为 70px 颜色为 #ffeb7b 字体是图标字体 electronicFont
-
no-hd 利用 after 和 before制作2个小角, 边框 2px solid #02a6b5 宽度为 30px 高度为 10px
-
小竖线 给 第一个小li after 就可以 1px宽 背景颜色为 rgba(255, 255, 255, 0.2); 高度 50% top 25% 即可
-
no-bd 里面也有两个小li 高度为 40px 文字颜色为 rgba(255, 255, 255, 0.7) 文字大小为 18px 上内边距为 10px
/* 声明字体*/ @font-face { font-family: electronicFont; src: url(../font/DS-DIGIT.TTF); }
中间部分分为上下两个模块

编写两个盒子
<div class="column"> <div class="no">上面数字模块</div> <div class="map">下面地图模块</div> </div>
编写样式
.column:nth-child(2) { flex: 5; margin: 0 0.125rem 0.1875rem; .no { background: rgba(101,132,226,0.1); // background: pink; padding: .1875rem; } }
效果:

上面的num部分也分为上面的数字和下面的文字两部分

编写上下两个盒子
<div class="column"> <div class="no"> <div class="no-hd">数字</div> <div class="no-bd">文字</div> </div> <div class="map">下面地图模块</div> </div>
编写样式
.column:nth-child(2) { flex: 5; margin: 0 0.125rem 0.1875rem; .no { background: rgba(101,132,226,0.1); // background: pink; padding: .1875rem; .no-hd { border: 1px solid rgba(25,186,139,0.17); } } }
两个数字通过ul下面的两个li来表示
<div class="column"> <div class="no"> <div class="no-hd"> <ul> <li>124124</li> <li>253242</li> </ul> </div> <div class="no-hd">文字</div> </div> <div class="map">下面地图模块</div> </div>
效果如下:

编写样式
.column:nth-child(2) { flex: 5; margin: 0 0.125rem 0.1875rem; .no { background: rgba(101,132,226,0.1); // background: pink; padding: .1875rem; .no-hd { border: 1px solid rgba(25,186,139,0.17); ul { display: flex; li { flex: 1; } } } } }
效果如下:

.column:nth-child(2) { flex: 5; margin: 0 0.125rem 0.1875rem; .no { background: rgba(101,132,226,0.1); // background: pink; padding: .1875rem; .no-hd { border: 1px solid rgba(25,186,139,0.17); ul { display: flex; li { flex: 1; line-height: 1rem; font-size: .875rem; color: #ffeb7b; } } } } }
效果如下:

下面去掉小圆点,并让文字居中显示,
li { list-style: none; }
字体是图标字体 electronicFont
先在font文件夹下面添加DS-DIGIT.TTF文件,再声明图标字体,如下所示:
/* 声明字体*/ @font-face { font-family: electronicFont; src: url(../font/DS-DIGIT.TTF); }
在通过font-family使用该字体
.column:nth-child(2) { flex: 5; margin: 0 0.125rem 0.1875rem; .no { background: rgba(101,132,226,0.1); // background: pink; padding: .1875rem; .no-hd { border: 1px solid rgba(25,186,139,0.17); ul { display: flex; li { flex: 1; line-height: 1rem; font-size: .875rem; color: #ffeb7b; text-align: center; font-family: "electronicFont"; } } } } }
效果如下:

编写左上和右下两个角,样式如下:
.no-hd { position: relative; border: 1px solid rgba(25,186,139,0.17); ul { display: flex; li { flex: 1; line-height: 1rem; font-size: .875rem; color: #ffeb7b; text-align: center; font-family: "electronicFont"; } } &::before { position: absolute; top: 0; left: 0; width: .375rem; height: .125rem; border-left: 2px solid #02a6b5; border-top: 2px solid #02a6b5; content: ""; } &::after { position: absolute; bottom: 0; right: 0; width: .375rem; height: .125rem; border-right: 2px solid #02a6b5; border-bottom: 2px solid #02a6b5; content: ""; } }
效果如下

中间的竖线样式编写:给第一个li添加after伪元素
ul { display: flex; li { position: relative; flex: 1; line-height: 1rem; font-size: .875rem; color: #ffeb7b; text-align: center; font-family: "electronicFont"; &::after { content: ""; position: absolute; top: 25%; right: 0; height: 50%; width: 1px; background: rgba(255,255,255,0.2); } } }
注意:子绝父相。
效果如下:

先在编写下面的文字部分:
<div class="no-bd"> <ul> <li>前端需求人数</li> <li>市场供应人数</li> </ul> </div>
编写样式
.no-bd { ul { display: flex; li { flex: 1; height: 0.5rem; line-height: .5rem; font-size: .225rem; color: rgba(255,255,255,0.7); text-align: center; font-family: "electronicFont"; padding-top: .125rem; } } }
效果如下:

地图模块制作:
-
地图模块高度为 810px 里面包含4个盒子: chart 放图表模块(地图后面再做)、 球体盒子、 旋转1、 旋转2。
-
球体图片模块 map1 大小为 518px 要加背景图片 因为要缩放100% 定位到最中央 透明度 .3
-
旋转1 map 2 大小为 643px 要加背景图片 因为要缩放100% 定位到中央 透明度 .6 做旋转动画 利用z-index压住球体
-
旋转2 map3 大小为 566px 要加背景图片 因为要缩放100% 定位到中央 旋转动画 注意是逆时针
<div class="map">下面地图模块</div>
编写map的样式
.map { height: 10.125rem; background-color: pink; }
效果如下:

编写球体盒子
<div class="map"> <div class="map1"></div> </div>
images文件夹中放入背景图片map.png
编写样式
.map { position: relative; height: 10.125rem; // background-color: pink; .map1 { width: 6.475rem; height: 6.475rem; background: url(../images/map.png); position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); background-size: 100% 100%; opacity: 0.3; } }
background-size第一个值指定图片的宽度,第二个值指定图片的高度。
效果如下:

旋转1编写
<div class="map2"></div>
images文件夹下添加lbx.png,
编写样式如下:
.map2 { width: 8.0375rem; height: 8.0375rem; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); background: url(../images/lbx.png); background-size: 100%, 100%; }
效果如下:

通过animation动画来实现不停的旋转,刚开始为0度,再旋转360度
.map2 { width: 8.0375rem; height: 8.0375rem; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); background: url(../images/lbx.png); background-size: 100%, 100%; // 调用动画 linear为匀速 infinite为无线循环 animation: rotate1 15s linear infinite; } // 定义动画 translate(-50%,-50%)保证居中旋转,从0度开始旋转,360结束 @keyframes rotate1 { from { transform: translate(-50%,-50%) rotate(0deg); } to { transform: translate(-50%,-50%) rotate(360deg); } }
发现背景图片旋转起来了

由于map2的div在map1的div下面,这样map2默认会压住map1,故不利用z-index压住球体。
编写旋转的箭头
<div class="map"> <div class="map1"></div> <div class="map2"></div> <div class="map3"></div> </div>
images文件夹中放入jt.png
如何实现逆时针旋转?从0度开始,到-360度结束
编写样式
.map3 { width: 7.075rem; height: 7.075rem; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); background: url(../images/jt.png); background-size: 100%, 100%; // 调用动画 linear为匀速 infinite为无线循环 animation: rotate2 10s linear infinite; } // 定义动画 translate(-50%,-50%)保证居中旋转,从0度开始旋转,360结束 @keyframes rotate2 { from { transform: translate(-50%,-50%) rotate(0deg); } to { transform: translate(-50%,-50%) rotate(-360deg); } }
效果如下:

编写地图模块
<div class="map"> <div class="map1"></div> <div class="map2"></div> <div class="map3"></div> <div class="chart">地图模块</div> </div>
编写样式
.chart { position: absolute; top: 0; left: 0; background-color: pink; width: 100%; height: 10.0125rem; }
效果如下:

这样地图就占据了map的大小。
浙公网安备 33010602011771号