当前位置: 首页 > Web前端 > JavaScript

可视化大屏的几种屏幕适配方案,总有一种是你需要的

时间:2023-03-27 18:33:48 JavaScript

.canvasBox{width:100vw;height:100vh;}.canvas{position:relative;}视觉大屏幕的几种屏幕适配方案,总有一个是你需要的屏幕,首先要考虑的问题之一就是如何让页面适配屏幕,因为我们一般是基于固定的宽高来构建或开发的,但实际屏幕可能大小不一,接下来我们将尝试几种简单通用的解决方案,并简要分析利弊。demo先写一个基本的demo,方便后续使用:importBarChartfrom"./components/BarChart.vue";importPieChartfrom"./components/PieChart.vue";importFunnelChartfrom"./components/FunnelChart.vue";//画布宽度和高度constcanvasWidth=ref(1920年);constcanvasHeight=ref(1080);//组件宽高constwidgetWidth=ref(960);constwidgetHeight=ref(540);.canvasBox{width:100vw;height:100vh;}.canvas{position:relative;}每个图表组件的宽度高度设置为100%,然后被Widget组件包裹,所以实际的宽高取决于Widget组件,Widget组件是绝对定位的,通过props传入width、height、position来模拟我们的拖拽操作,为了简单起见,我们将所有图表的宽高设置为相同小部件组件:.widgetBox{位置:绝对;}组件的整体容器是类名为canvas的元素,相对定位,宽高也是动态设置的。canvas元素的父canvasBox元素的宽高设置为与屏幕宽高一致。固定大小意味着宽度和高度是固定的。如果宽度和高度小于屏幕宽度和高度,它将在屏幕上居中。这是最简单的解决方法,相当于不适合屏幕。canvas配置的大小其实就是大小,不随屏幕的变化而变化。因此,配置后各个组件的宽高不会发生变化。它一般用于固定尺寸和以后不会改变的大视觉屏幕。我们之前的demo一开始是这样的:当然,如果宽高小于屏幕,还需要加上居中的逻辑。居中的方法有很多种。可以使用css和js,根据自己的喜好来做://画布的位置constcanvasLeft=ref(0);constcanvasTop=ref(0);//如果屏幕的宽度或高度大于画布,则居中显示letwindowWidth=window.innerWidth;letwindowHeight=window.innerHeight;if(windowWidth>canvasWidth.value){canvasLeft.value=(windowWidth-canvasWidth.value)/2;}if(windowHeight>canvasHeight.value){canvasTop.value=(windowHeight-canvasHeight.value)/2;}

确定窗口的宽高是否大于画布的宽高,如果是,则通过left或top调整:自适应宽度是指宽度适应屏幕,高度保持不变。这种方案的缺点是垂直方向会有滚动条。比如canvas设置的宽度是1920,但是屏幕的实际宽度是1280,那么缩小1.5倍,那么canvas和各个组件的宽度也需要同时缩小1.5倍,并且每个组件的左值也需要动态调整。首先实现容器元素canvas的尺寸调整://保存原画布的宽度constoriginCanvasWidth=ref(canvasWidth.value);//宽度缩放constratioWidth=ref(1);//当前窗口的宽度letwindowWidth=window.innerWidth;//设置画布宽度为当前窗口的宽度canvasWidth.value=windowWidth;//计算当前宽度与原始宽度的比例ratioWidth.value=windowWidth/originCanvasWidth.value;然后将这个比例传给Widget组件Adjustment:在Widget组件中,我们只需要乘以宽度和左边的这个比例。为什么乘法很简单:newWidth/width=ratioWidth=windowWidth/originCanvasWidthnewWidth=width*ratioWidth//left也可以看成是从左边开始的宽度
自适应屏幕是Bothwidth和height是自适应的,相对于之前的方案,这种横向和纵向不会有滚动条,可以完全覆盖屏幕,适配即可。//画布原始宽高constoriginCanvasWidth=ref(canvasWidth.value);constoriginCanvasHeight=ref(canvasHeight.value);//缩放constratioWidth=ref(1);constratioHeight=ref(1);//当前窗口letwindowWidth=window.innerWidth;letwindowHeight=window.innerHeight;//设置画布的宽高为当前窗口的宽高canvasWidth.value=windowWidth;canvasHeight.value=windowHeight;//计算当前宽高和原来的RatioWidth.value=windowWidth/originCanvasWidth.value;ratioHeight.value=windowHeight/originCanvasHeight.value;也将比例传递给Widget组件进行调整:">
整体比例缩放是利用css的transform属性做组件容器画布整体保持原来的比例,显示在屏幕中央。当然,你可以选择只缩放宽度或高度,但这会扭曲前面的两个解决方案。在开发我们的组件时,我们必须考虑到容器的宽度和高度,也就是我们需要进行调整。不过宽高比实在是太极端了,不好处理,显示效果肯定比较差,但是这种整体比例适配就不需要考虑这种情况了。在实际项目中,如果有大屏幕需要适配屏幕,我一般采用这种方式。优点是简单,缺点是横向或纵向可能会有空白,但背景是全屏的,效果不会差。实现也非常简单。计算画布的原始比例,然后计算屏幕的比例,然后判断是宽度与屏幕一致高度自适应,还是高度与屏幕一致宽度自适应://current窗口宽高比letwindowWidth=window.innerWidth;letwindowHeight=window.innerHeight;letwindowRatio=windowWidth/windowHeight;//画布的原始宽高比constcanvasRatio=canvasWidth.value/canvasHeight.value;//计算适配后画布的新宽高letnewCanvasWidth=0;letnewCanvasHeight=0;if(canvasRatio>windowRatio){//画布的纵横比大于屏幕的纵横比//画布宽度调整为屏幕宽度newCanvasWidth=windowWidth;//画布的高度以画布原来的比例为基础ScalenewCanvasHeight=windowWidth/canvasRatio;}else{//画布的纵横比小于屏幕的纵横比//画布的高度调整为屏幕的高度newCanvasHeight=windowHeight;//画布的宽度按照画布原来的比例缩放newCanvasWidth=windowHeight*canvasRatio;}//...假设屏幕宽高相同,则比例为1。第一种情况,假设canvas的宽度是高度的两倍,那么比例就是2。要保持原来的比例2适应屏幕,显然只有宽度和屏幕一致,高度是自适应的,因为如果高度和屏幕一致,那么宽度需要是高度的两倍,屏幕显然无法显示:第二种情况,假设画布的高度是宽度的两倍,那么比率为0.5。保持0.5的比例适合屏幕,高度需要和屏幕保持一致,宽度是自适应的:计算画布适应屏幕新的宽高后,可以计算它相对于画布原始宽高://...//相对于画布原始宽高的缩放比例constcanvasStyle=reactive({transform:"",});constscaleX=newCanvasWidth/canvasWidth.value;constscaleY=newCanvasHeight/canvasHeight.value;canvasStyle.transform=`scale(${scaleX},${scaleY})`给容器元素画布添加样式只需:
显示的位置好像有问题,这其实是因为默认情况下,元素的变换是基于自身的中心点作为原点:我们只需要将其改为左上角作为原点即可:constcanvasStyle=reactive({transform:"",transformOrigin:`lefttop`//改为左上角作为变换原点});最后,让它居中://居中consttranslateX=(windowWidth-newCanvasWidth)/2/scaleX;consttranslateY=(windowHeight-newCanvasHeight)/2/scaleY;canvasStyle.transform=`scale(${scaleX},${scaleY})翻译(${translateX}px,${translateY}px)`;window的宽高减去canvas适配后的新宽高,即剩余空间,然后除以2为居中显示,为什么要除以zoom值,因为translate的值也会用scale缩放,比如translateX计算为100,scaleX为0.5,那么实际最终的offset是100*0.5=50,显然是错误的,所以我们除以一个缩放值来offset这个方案貌似很完美,请问有没有什么问题,明显有,一个小问题是缩放后文字可能会模糊,这个问题不大,我遇到的另一个问题是如果使用getBoundingClientRect方法获取elementinformation,本意是获取元素的原始尺寸数据,但是缩放后返回的是缩放后的数据,所以可能会偏离我们的初衷,比如有一个div如下:我们要根据这个的大小和位置动态复制一个divdiv:const{width,height}=el1.value.getBoundingClientRect();const{left,top}=window.getComputedStyle(el1.value);el2.value.style.width=`${width}px`;el2.value.style.height=`${height}px`;el2.value.style.left=left;el2.value.style.top=顶部;看到得到的aspect比实际的要小一点,这显然不是我们需要的。解决办法要么不使用getBoundingClientRect方法,而是使用offsetWdith等不受缩放影响的方法或属性获取元素大小,要么获取数据除以缩放值。当然也可能有其他的属性或者方法也有这个问题,需要大家在实际开发中去测试。小结本文简单总结了几种大屏适配的方法。没有一个是最好的,也没有一个是完美的。没有办法,很多时候需要做出一定的妥协。Demo地址:https://wanglin2.github.io/visual-drag-platform-fit-demo/demo仓库地址:https://github.com/wanglin2/visual-drag-platform-fit-demo