完成效果
访问地址:http://106.75.179.94/bigscreen/#/
源码虽然全是我写的,但是属于公司,所以不发出来
使用的是vue2,dataV,echart
大屏实践案例:
dataV组件库和文档:
gitee.com/jiasichen/d… datav.jiaminghi.com/guide/#%E7%… charts.jiaminghi.com/config/
echart案例库:
echart学习:
先看:www.runoob.com/echarts/ech…
再看:echarts.apache.org/zh/option.h…
最后看(完整大全)www.bbsmax.com/A/nAJvKq9G5…
案例里可取的点
项目部分模仿下面这个案例的: gitee.com/zhufei_yao/…
rem适配
var width = docEl.getBoundingClientRect().width;
var docEl = doc.documentElement;
// 设置成24等份,设计稿时1920px的,这样1rem就是80px
var rem = width / 24;
docEl.style.fontSize = rem + "px";
grid布局
grid-template-columns: 2fr 3fr 5fr 3fr 2fr;
我因为不习惯换成flex 配合rem了
resize时也要更新chart
当窗口resize时,自动调用chart.resize
created() {
let timer = null;
//可以加个防抖
window.addEventListener(
"resize",
() => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
this.$echarts.init(document.getElementById("bodyChart")).resize();
}
}, 300);
},
false
);
},
或者学上面案例的,使用mixins混入,那么图表chart就要写在data里。
个人采取的自适应方案
先分成上下几块,用vh来限定高度 左右的用rem,就用案例那样的 resize的时候获取clientWidth,再/24,确保24rem等于宽度100% 我中间三块,可以用0.2rem的padding,5.8,12,5.8,0.2的padding
也可以用width:25%,50%,25%
也可以用flex
也可以用案例的grid
echart基本配置
var option = {
//标题
title: {
text: '第一个 ECharts 实例'
},
tooltip: {},//提示框
legend: {//图例图形
data:['销量']
},
xAxis: {//配置要在 X 轴显示的项:
data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
},
yAxis: {},//配置要在 Y 轴显示的项。
series: [{
name:'销量',// 系列名称
type: 'bar',// 系列图表类型
tooltip: {//是否显示提示框
show: false,
},
data: [5, 20, 36, 10, 10, 20],//数据
}]
};
bar: {
barMinHeight: 0, // 最小高度改为0
// barWidth: null, // 默认自适应
barGap: '30%', // 柱间距离,默认为柱形宽度的30%,可设固定值
barCategoryGap : '20%', // 类目间柱形距离,默认为类目间距的20%,可设固定值
itemStyle: {
normal: {
// color: '各异',
barBorderColor: '#fff', // 柱条边线
barBorderRadius: 0, // 柱条边线圆角,单位px,默认为0
barBorderWidth: 1, // 柱条边线线宽,单位px,默认为1
label: {
show: false
// position: 默认自适应,水平布局为'top',垂直布局为'right',可选为
// 'inside'|'left'|'right'|'top'|'bottom'
// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
}
},
emphasis: {//高亮的样式
// color: '各异',
barBorderColor: 'rgba(0,0,0,0)', // 柱条边线
barBorderRadius: 0, // 柱条边线圆角,单位px,默认为0
barBorderWidth: 1, // 柱条边线线宽,单位px,默认为1
label: {
show: false
// position: 默认自适应,水平布局为'top',垂直布局为'right',可选为
// 'inside'|'left'|'right'|'top'|'bottom'
// textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
}
}
}
},
类目轴配置
也就是一般的柱形type: "category",
默认色板
// 默认色板
color: ['#ff7f50','#87cefa','#da70d6','#32cd32','#6495ed',
'#ff69b4','#ba55d3','#cd5c5c','#ffa500','#40e0d0',
'#1e90ff','#ff6347','#7b68ee','#00fa9a','#ffd700',
'#6699FF','#ff6666','#3cb371','#b8860b','#30e0e0'],
#xAxis
type = 'category' 类目轴
目前我只看类目轴的属性 可通过 xAxis.data 设置类目数据
show = true 是否显示 x 轴。
position 'top'、'bottom' 坐标在下还是在上
offset 偏移坐标
name 坐标轴名字 目前不需要,相关的不看
inverse 反转
boundaryGap 两边留白 默认为 true
min 坐标轴刻度最小值。类目轴不用关心这个
max 坐标轴刻度最大值。
triggerEvent 坐标轴的标签是否响应和触发鼠标事件
axisLine 坐标轴轴线相关设置。
show = true 是否显示坐标轴轴线
lineStyle 坐标轴线
xAxis.axisLine.lineStyle. color = '#333' 坐标轴线线的颜色。
axisTick 坐标轴刻度
axisLabel 坐标轴刻度标签
axisLabel. color 刻度标签文字的颜色;支持回调函数
fontStyle
fontWeight
fontFamily
fontSize
align 文字水平对齐方式,默
verticalAlign 文字垂直对齐方式,
lineHeight
backgroundColor 文字块背景色。
borderColor
borderWidth
borderRadius
padding
阴影
文字块的宽度
高度
textBorderColor 文字本身的描边颜色
rich 在 rich 里面,可以自定义富文本样式。利用富文本样式,可以在标签中做出非常丰富的效果。
splitLine 坐标轴在 grid 区域中的分隔线。
data 类目轴的数据,设置了就说明是类目轴;
data. textStyle有以下标签属性
{ color , fontStyle , fontWeight , fontFamily , fontSize , align , verticalAlign , lineHeight , backgroundColor , borderColor , borderWidth , borderRadius , padding , shadowColor , shadowBlur , shadowOffsetX , shadowOffsetY , width , height , textBorderColor , textBorderWidth , textShadowColor , textShadowBlur , textShadowOffsetX , textShadowOffsetY , rich }
横向类目轴
亮晶晶
前面一段代码是数据的,可以不用管,需要知道的是顺序,坐标是从下到上拿数据的,阴影的颜色应该和本来的颜色一致,这样才会亮晶晶,轴长由data转变成
{value:xx, itemStyle: {
normal: {
borderWidth: 1,
shadowBlur: 20,
borderColor: color[i],
shadowColor: color[i],
},
},}
组成的数组。 具体为 标签:数组showName
0: "肾上腺"
1: "头颈"
2: "肾"
3: "眼睛"
4: "肝"
5: "肺"
轴:数组对象Array(6)
0:
itemStyle: Object
normal: Object
borderColor: "#00ffff"
borderWidth: 1
shadowBlur: 20
shadowColor: "#00ffff"
value:1
1: {__ob__: Observer}
2: {__ob__: Observer}
3: {__ob__: Observer}
4: {__ob__: Observer}
5: {__ob__: Observer}
//颜色列表
let colorList = [
"#00ffff",
"#006ced",
"#00cfff",
"#ffe000",
"#ffa800",
"#ff5b00",
];
//取出病症的值,深拷贝 解除引用 以便排序
let arr = JSON.parse(
JSON.stringify(this.$store.state.res?.dataShareSiteList)
);
function arrayObjSortByKey(array, key) {
return array.sort(function (a, b) {
var x = a[key];
var y = b[key];
return x > y ? -1 : x < y ? 1 : 0;
});
}
//数组对象,按照对象的属性进行排序
arrayObjSortByKey(arr, "total");
//只取前四个最大的来展示,如果第一大和其他差距超过8倍,就不要其他了
for (let i = 0; i < 6; i++) {
let color = [
"#00ffff",
"#006ced",
"#00cfff",
"#ffe000",
"#ffa800",
"#ff5b00",
].reverse();
// if(arr[0]&&i!=0&&arr[0].total/arr[i].total>8){
// break;
// }
this.showName.push(arr[i].name);
this.showValue.push({
value: arr[i].total,
//自定义标签样式,仅对该数据项有效
//自定义特殊 itemStyle,仅对该数据项有效
itemStyle: {
normal: {
borderWidth: 1,
shadowBlur: 20,
borderColor: color[i],
shadowColor: color[i],
},
},
});
}
let chart2 = this.$echarts.init(
document.getElementById("little-body-chart")
);
chart2.setOption({
grid: [
{
x: "32%",
y: "0%",
width: "50%",
height: "100%",
},
],
xAxis: [
{
gridIndex: 0,
axisTick: {
show: false,
},
axisLabel: {
show: false,
},
splitLine: {
show: false,
},
axisLine: {
show: false,
},
},
],
yAxis: [
{
data: this.showName.reverse(),
axisTick: {
show: false,
},
axisLabel: {
show: true,
color: "#fff",
rich: {
a: {
color: "red",
lineHeight: 10,
},
},
},
splitLine: {
show: false,
},
axisLine: {
show: false,
lineStyle: {
color: "#6173a3",
},
},
},
],
series: [
{
type: "bar",
barWidth: "20%",
itemStyle: {
normal: {
color: function (params) {
return colorList[params.dataIndex];
},
// color: '#86c9f4'
},
},
data: this.showValue.reverse(),
},
],
});
地图学习
解说上面的案例:www.jb51.net/article/199… www.makeapie.com/explore.htm…
地图钻取:
w3c地图教程:www.w3cschool.cn/echarts_tut…
ECharts 地图绘制与钻取简易接口
example.maxiaoqu.com/map-geoJson…
地图属性: www.cnblogs.com/zhangxiaoxi…
取图网站: datav.aliyun.com/tools/atlas…
取图和加载
我要实现的是广东+澳门和香港;下载全国json文件,可以看到每个地点是一个对象;拿下想要的地方的对象字段就可以随意组合了 于是我在全国里找到了澳门和香港的json相关字段。加到了广东json文件里。就可以了
地图加载也可以不用jq的xhr获取,改用 本地json获取,使用require语法,这里感谢小单的帮忙;我这被误导以为只能xhr获取或者js加载
#vue
<script>
let guangdongJson = require('./guangdong.json')
export default {
data() {
return {
chart:null,
};
},
mounted() {
this.initMap();
},
methods: {
initMap() {
var echarts = this.$echarts
this.chart = echarts.init(document.getElementById("bottomLeft"));
this.chart.hideLoading();
echarts.registerMap("广东", guangdongJson);
地图中鼠标移入移除事件
地图鼠标移入不变色: blog.csdn.net/qq_38402878…
常见actionAPI: www.cnblogs.com/sminocence/…
鼠标移入移除事件:
blog.csdn.net/qq_36895045… www.cnblogs.com/xtreme/p/13…
this.chart.setOption(option);
this.chart.on('mouseover',(params)=>{
console.log(params,params.name)
let xiao = document.getElementById('showTip')
var evt = params.event;
xiao.style.left = evt.offsetX-200+'px';
xiao.style.top = evt.offsetY+'px';
if(params.componentType=='geo'){
xiao.innerHTML = '<div style="background:#fff;border-radius:10px;padding-top:10px;box-shadow:0 0 10px #666">' +
'<div style="color:#fff;height:20px;border-radius:6px;font-size:12px;line-height:20px;background-color:#5861a2;text-align:center;margin:0 2px;">' +
params.name +
"</div>" +
'<div style="text-align:center;color:#494949;padding:8px 6px">' +
'<span style="font-size:18px;font-weight:bold;">' +
"节点:" +
params.name +
" " +
"</span>" +
"</div>" +
"</div>";
}
})
this.chart.on('mouseout',function(p){
let xiao = document.getElementById('showTip')
xiao.innerHTML = ''
});
- 鼠标移入类目轴标签事件
参考:www.jianshu.com/p/5d9e0d664…
这里是y轴标签,所以在 yAxis里设置
yAxis: [{
triggerEvent:true
}],
chart.on('mouseover', function (params) {
//标签名字显示在value
//柱子显示在name
console.log(params.name||params.value);
});
简单的地图绘制
案例:
不知道是干嘛的字段,删掉再看看是什么地方没了就知道是干嘛的了
或者稍微改一下,对比一下
echarts.apache.org/examples/zh… www.makeapie.com/editor.html…
#template
<div @click="changeMap('map')" v-show="nowShow=='map'" id="littleMap" style='width:5rem;height:258px;cursor:pointer'></div>
#mounted
let guangdongJson = require('./guangdong.json') //放<script>
let chart = this.$echarts.init(document.getElementById("littleMap"));
chart.hideLoading();
this.$echarts.registerMap("guangdong", guangdongJson);
chart.setOption({
// backgroundColor: "#404a59",
geo: {
map: 'guangdong',
show: true,
roam: false,
label: {
emphasis: {
show: false
}
},
layoutSize: "100%",
itemStyle: {
normal: {
borderColor: "rgba(147, 235, 248, 1)",
borderWidth: 1,
areaColor: {
type: "radial",
x: 0.5,
y: 0.5,
r: 0.8,
colorStops: [
{
offset: 0,
color: "rgba(147, 235, 248, 0)", // 0% 处的颜色
},
{
offset: 1,
color: "rgba(147, 235, 248, .2)", // 100% 处的颜色
},
],
globalCoord: false, // 缺省为 false
},
shadowColor: "rgba(128, 217, 248, 1)",
// shadowColor: 'rgba(255, 255, 255, 1)',
shadowOffsetX: -2,
shadowOffsetY: 2,
shadowBlur: 10,
},
}
},
series: [{
type: 'map',
map: 'guangdong',
// aspectScale: 0.75,
label: {
normal: {
show: false,
},
emphasis: {
show: false,
}
},
itemStyle: {
normal: {
areaColor: {
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0,
color: '#073684' // 0% 处的颜色
}, {
offset: 1,
color: '#061E3D' // 100% 处的颜色
}],
},
borderColor: '#215495',
borderWidth: 1,
},
},
}, ]
})
翻牌效果
<NumberCard :countStr="serverCount"></NumberCard>
#NumberCard.vue
<template>
<div class="demo">
<ul class="fp-box">
<!-- 默认进来是7位,超过自动加 -->
<li
ref="li"
v-for="i in countStr.toString().length"
:key="i"
>
<!-- 每列中的10行数字 -->
<span v-for="num in 10" :key="num">
<span class="line"></span>
<!-- {{ num - 1 }} -->
<span class="num-wrap">{{ num - 1 }}</span>
</span>
</li>
</ul>
</div>
</template>
<script>
export default {
props: {
countStr: Number,
},
data() {
return {
numberArr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], //固定每列中的19行数字
numStr: "", // 需要展示的数字字符串
numArr: [0, 0, 0, 0, 0, 0, 0], //默认展示7个数字数组
// countStr: "", // 需要展示的数字
};
},
mounted() {
//this.countStr = "1132";
this.initNumCard();
},
watch:{
countStr(){
this.initNumCard()
}
},
methods: {
// 初始化数字卡片
initNumCard() {
this.numStr = this.countStr.toString();
this.numArr = this.numStr.split("");
let numArrlen = this.numArr.length;
// 展示数字的处理,不够7位前面补0
// 默认进来是7位,超过自动加
this.$refs.li.forEach((item, index) => {
let ty = this.numArr[index];
// 滚动数字(li标签)
item.style.transform = `translateY(-${ty * 47}px)`;
});
},
},
};
</script>
<style lang="scss" scoped>
.fp-box {
display: flex;
overflow: hidden;
li {
width: 30px;
height: 47px;
flex-direction: column;
transition: transform 1s ease-in-out;
margin-right: 4px;
& > span {
text-align: center;
font-size: 24px;
color: #3de7c9;;
display: flex;
display: inline-block;
width: 30px;
height: 47px;
line-height: 47px;
position: relative;
// .line {
// display: inline-block;
// height: 1px;
// background: #001347;
// width: 100%;
// position: absolute;
// left: 0;
// top: 23px;
// }
}
}
}
</style>
参考:www.jianshu.com/p/1441dc217…
柱形图定时切换
#切换很简单,这个柱形图是个组件,只要我传入的props数据改变,就会相应的变化
<customBottomRightChart :type="switchName"/>
#柱形组件
<template>
<div>
<div id="bottomRightChart" style="height: 4.4rem"></div>
</div>
</template>
<script>
export default {
props:["type"],
mounted() {
this.draw();
},
watch:{
type(vlue){//这里保险一点
console.log(vlue)
this.draw()
}
},
computed:{
},
mixins: [echartMixins],
methods: {
draw() {
// 基于准备好的dom,初始化echarts实例
this.chart = this.$echarts.init(
document.getElementById("bottomRightChart")
);
this.chart.setOption(option1);
if(this.type=='上传'){
this.chart.setOption(option1);
}else if(this.type=='浏览'){
this.chart.setOption(option2);
}else if(this.type=='计算'){
this.chart.setOption(option3);
}
},
},
};
</script>
#父组件
<template>
<div id="bottomRight" @mouseover="stopInterval" @mouseout="intervalChart">//鼠标移入就清除定时切换,移出时再次设置定时切换
<div class="bg-color-black">
<div class="d-flex pt-2 pl-2" style='justify-content:space-between'>
<div class="d-flex">
<span style="color:#5cd9e8">
<icon name="chart-area"></icon>
</span>
<div class="d-flex">
<span class="fs-xl text mx-2">历史数据 共{{total}}次</span>
</div>
</div>
<p style='color:grey;font-size:0.2rem'>
<span :class="{ active: switchName=='上传'}" style="cursor:pointer;border-right:1px solid white;padding-right:4px" @click="select('上传')"> 上传</span>
<span :class="{ active: switchName=='浏览'}" style="cursor:pointer;border-right:1px solid white;padding-right:4px" @click="select('浏览')"> 浏览</span>
<span :class="{ active: switchName=='计算'}" style="cursor:pointer" @click="select('计算')"> 计算</span>
</p>
</div>
<div >
<!-- <div style="margin-top:0.3rem;margin-bottom:0.3rem"> -->
<customBottomRightChart :type="switchName"/>
</div>
</div>
</div>
</template>
<script>
import customBottomRightChart from "@/components/echart/bottom/customBottomRightChart";
export default {
data() {
return {
total:0,
switchName:'上传',
interval:null
};
},
components: {
customBottomRightChart
},
mounted() {
this.total = this.$store.state.res?.dataShareCount
this.intervalChart();
},
methods: {
select(name){//手动切换
this.switchName = name;
if(this.switchName == '上传'){
this.total = this.$store.state.res?.dataShareCount
} else if(this.switchName == '浏览'){
this.total = this.$store.state.res?.dataBrowseCount
} else if(this.switchName == '计算'){
this.total = this.$store.state.res?.calculateDataCount
}
},
stopInterval(){//清除切换
clearInterval(this.interval);
},
intervalChart(){//定时切换
this.interval = setInterval(()=>{
if(this.switchName == '上传'){
this.switchName = '浏览'
} else if(this.switchName == '浏览'){
this.switchName = '计算'
} else if(this.switchName == '计算'){
this.switchName = '上传'
}
},2000)
}
}
};
</script>
默认全屏
全屏只能由用户主动触发,程序设置的自动全屏会被阻挡
可以用按钮来提示用户点击触发全屏
template
<div
style="position: fixed; top: 0%; left: 30%; z-index: 500"
@click="f11"
>
点击全屏显示
</div>
methods:{
f11() {
console.log("f11");
function requestFullScreen(element) {
var requestMethod =
element.requestFullScreen ||
element.webkitRequestFullScreen ||
element.mozRequestFullScreen ||
element.msRequestFullScreen;
if (requestMethod) {
requestMethod.call(element);
} else if (typeof window.ActiveXObject !== "undefined") {
var wscript = new ActiveXObject("WScript.Shell");
if (wscript !== null) {
wscript.SendKeys("{F11}");
wscript.SendKeys("{F5}");
}
}
}
//默认全屏显示
var elem = document.getElementsByTagName("html")[0];
requestFullScreen(elem);
},
}
不过按刷新会退出全屏,很无奈,我的需要全屏后还需要刷新来让元素适应屏幕,不然就需要对元素一个一个进行width100,height100的设置,所以我就放弃了,诶。。
遇到的一些问题
- 有碰到后端同学帮我打包的弄上服务器后,找不到资源的情况 此时把history改为hash即可
- 由于没有用webpack生成html,此时的title是package.json的name,又换不成中文 此时就把打包生成的html里的title改了就好