大屏可视化:完美自适应的解决方案

news2024/11/15 9:48:52

你好,我是沐爸,欢迎点赞、收藏、评论和关注。

昨天我们聊到阿里 DataV 大屏的五种自适应方案,每一种多少都有些瑕疵,如果没有看过昨天的博客,回头可以了解下:链接

可视化大屏如何完美适配屏幕?有一种方案,或者说一种思想,那就是随着屏幕的缩放,页面元素(字体、宽高、间距等)也随之缩放。虽然称为完美方案,但也不能自适应特别极端的情况,如屏幕过宽或过长,我们尽量考虑正常尺寸。

今天的分享很简单,只提供代码和预览效果,需要你亲自去运行,去尝试。

一、效果预览

二、代码实现

使用的最容易上手的 Vue2 框架,安装了两个依赖 `echarts`和 `lodash`
npm install echarts lodash

src/App.vue

<template>
    <div id="app">
        <div class="bg">
            <div class="preview-main">
                <ChartComponent v-for="item in list" :key="item.id" :item="item" :scaleWidth="scaleWidth"
                    :scaleHeight="scaleHeight"></ChartComponent>
            </div>
        </div>
    </div>
</template>

<script>
import ChartComponent from './components/ChartComponent.vue'
import { list } from './data'

export default {
    components: {
        ChartComponent
    },
    data() {
        return {
            list,
            scaleWidth: window.innerWidth / 1600,
            scaleHeight: window.innerHeight / 900
        }
    },
    mounted() {
        window.addEventListener('resize', () => {
            this.scaleWidth = window.innerWidth / 1600
            this.scaleHeight = window.innerHeight / 900
        })
    }
}
</script>

<style scoped>
.bg {
    width: 100%;
    height: 100vh !important;
    min-width: 200px;
    min-height: 300px;
    background-color: rgb(242, 242, 242);
    padding: 5px;
    box-sizing: border-box;
}

.preview-main {
    width: 100%;
    height: 100%;
    position: relative;
}
</style>

<style>
html {
    height: 100%;
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    overflow: hidden;
}
</style>

src/data.js

export const list = [
    {
        id: 'c0',
        style: {
            width: 1590,
            height: 100,
            left: 0,
            top: 0
        },
        type: 'html',
        template: `
            <div style="font-size:28px;width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;">
                2021年全国GDP数据
            </div>
        `
    },
    {
        id: 'c1',
        style: {
            width: 397,
            height: 395,
            left: 0,
            top: 100
        },
        type: 'chart',
        option: {
            title: {
                text: '今年上半年GDP产业分布(亿元)',
                left: 10,
                top: 10,
                textStyle: {
                    color: '#303133',
                    fontWeight: 'normal',
                    fontSize: 18
                }
            },
            color: ['#EF8B07', '#FAE37C', '#F5C021',],
            tooltip: {
                trigger: 'item'
            },
            legend: {
                bottom: '10',
                left: 'center',
                icon: 'rect',
                itemWidth: 10,
                itemHeight: 10
            },
            series: [
                {
                    name: 'GDP',
                    type: 'pie',
                    radius: ['41%', '55%'],
                    avoidLabelOverlap: false,
                    label: {
                        show: true,
                        position: 'inside',
                        formatter: '{c}'
                    },
                    data: [
                        { value: 28402, name: '第一产业' },
                        { value: 207154, name: '第二产业' },
                        { value: 296611, name: '第三产业' }
                    ]
                }
            ]
        },

    },
    {
        id: 'c2',
        style: {
            width: 397,
            height: 395,
            left: 0,
            top: 495
        },
        type: 'chart',
        option: {
            color: ['#F8B65E'],
            title: {
                text: 'GDP前十强城市',
                left: 10,
                top: 10,
                textStyle: {
                    color: '#303133',
                    fontWeight: 'normal',
                    fontSize: 18
                }
            },
            grid: {
                left: '15',
                right: '15',
                containLabel: true
            },
            legend: {
                bottom: '10',
                left: 'center',
                icon: 'rect',
                itemWidth: 10,
                itemHeight: 10
            },
            xAxis: {
                type: 'value',
                splitLine: {
                    show: false
                },
                axisLabel: {
                    show: false
                }
            },
            yAxis: {
                type: 'category',
                axisLine: {
                    show: false
                },
                axisTick: {
                    show: false
                },
                data: ['南京市', '武汉市', '杭州市', '成都市', '苏州市', '重庆市', '广州市', '深圳市', '北京市', '上海市'].reverse()
            },
            series: [
                {
                    name: 'GDP(亿元)',
                    type: 'bar',
                    label: {
                        show: true,
                        position: 'right',
                        formatter: '{c}'
                    },
                    data: [7622.77, 8251.5, 8656.03, 9602.72, 10684.66, 12903, 13101.89, 14324.47, 19228, 20102].reverse()
                }
            ]
        }
    },
    {
        id: 'c3',
        style: {
            width: 663,
            height: 698,
            left: 397,
            top: 190
        },
        type: 'map',
        option: {
            title: {
                text: '今年上半年GDP',
                left: 10,
                top: 10,
                textStyle: {
                    color: '#303133',
                    fontWeight: 'normal',
                    fontSize: 18
                }
            },
            visualMap: {
                min: 0,
                max: 1000,
                left: 'right',
                top: 'bottom',
                text: ['Hign', 'Low'],
                calculable: true,
                color: ['#B77702', '#FCF4E5']
            },
            geo: {
                map: "china",
                zoom: 1,
                roam: true,
                top: "20%",
                label: {
                    show: true
                },
            },
            series: [
                {
                    type: "map",
                    geoIndex: 0,
                    data: [
                        { name: '上海市', value: 20102 },
                        { name: '云南省', value: 12680.22 },
                        { name: '内蒙古自治区', value: 8312.84 },
                        { name: '北京市', value: 19228 },
                        { name: '吉林省', value: 6075.01 },
                        { name: '四川省', value: 25232.36 },
                        { name: '天津市', value: 7309 },
                        { name: '安徽省', value: 20565.77 },
                        { name: '山东省', value: 38610.25 },
                        { name: '山西省', value: 9606.81 },
                        { name: '广东省', value: 57226.27 },
                        { name: '广西壮族自治区', value: 5525.09 },
                        { name: '新疆维吾尔自治区', value: 7329 },
                        { name: '江苏省', value: 54890.37 },
                        { name: '江西省', value: 13977.22 },
                        { name: '河北省', value: 18754.04 },
                        { name: '河南省', value: 22719.34 },
                        { name: '浙江省', value: 34514.84 },
                        { name: '海南省', value: 2884.31 },
                        { name: '湖北省', value: 22732.1 },
                        { name: '湖南省', value: 21671.12 },
                        { name: '甘肃省', value: 4748.17 },
                        { name: '福建省', value: 22899.31 },
                        { name: '西藏自治区', value: 926.05 },
                        { name: '贵州省', value: 9075.48 },
                        { name: '辽宁省', value: 12641.2 },
                        { name: '重庆市', value: 12903 },
                        { name: '陕西省', value: 13454.73 },
                        { name: '青海省', value: 1557 },
                        { name: '黑龙江省', value: 5990 }
                    ]
                }
            ]
        }
    },
    {
        id: 'c4',
        style: {
            width: 530,
            height: 395,
            left: 1060,
            top: 100
        },
        type: 'chart',
        option: {
        color: ['#F6EA51'],
        title: {
            text: '全国百强县分布',
            left: 'center',
            top: 10,
            textStyle: {
                color: '#303133',
                fontWeight: 'normal',
                fontSize: 18
            }
        },
        grid: {
            left: '15',
            right: '15',
            containLabel: true
        },
        legend: {
            bottom: '10',
            left: 'center',
            icon: 'rect',
            itemWidth: 10,
            itemHeight: 10,
            data: ['GDP(亿元)']
        },
        xAxis: {
            data: ['内蒙古自治区', '安徽省', '山东省', '广东省', '新疆维吾尔自治区', '江苏省', '江西省', '河北省', '河南省', '浙江省', '湖北省', '湖南省', '福建省', '贵州省', '辽宁省', '陕西省']
        },
        yAxis: {
            name: '百强县个数'
        },
        tooltip: {
            type: 'category',
            formatter: function (value) {
                // GDP数据
                let gdpArr = [8312.84, 20565.77, 38610.25, 57226.27, 7329, 54890.37, 13977.22, 18754.04, 22719.34, 34514.84, 22732.1, 21671.12, 22899.31, 9075.48, 12641.2, 13454.73];

                return `${value.name},${value.value},${gdpArr[value.dataIndex]}`
            }
        },
        series: [
            {
                type: 'scatter',
                name: 'GDP(亿元)',
                data: [2, 2, 13, 4, 1, 26, 1, 2, 7, 18, 7, 5, 9, 1, 1, 1], // 百强县数量
                symbolSize: function (value, item) {
                    // GDP数据
                    let gdpArr = [8312.84, 20565.77, 38610.25, 57226.27, 7329, 54890.37, 13977.22, 18754.04, 22719.34, 34514.84, 22732.1, 21671.12, 22899.31, 9075.48, 12641.2, 13454.73];

                    return gdpArr[item.dataIndex] / 1000
                }
            }
        ]
    }
    },
    {
        id: 'c5',
        style: {
            width: 530,
            height: 395,
            left: 1060,
            top: 495
        },
        type: 'chart',
        option: {
            color: ['#EF8B07'],
            title: {
                text: '历年GDP数据',
                left: 10,
                top: 10,
                textStyle: {
                    color: '#303133',
                    fontWeight: 'normal',
                    fontSize: 18
                }
            },
            grid: {
                left: '15',
                right: '15',
                containLabel: true
            },
            legend: {
                bottom: '10',
                left: 'center',
                icon: 'rect',
                itemWidth: 10,
                itemHeight: 10
            },
            xAxis: {
                type: 'category',
                boundaryGap: false,
                data: ['2011', '2012', '2013', '2014', '2015', '2016', '2017', '2018', '2019', '2020']
            },
            yAxis: {
                type: 'value',
                splitLine: {
                    show: false
                }
            },
            tooltip: {
                type: 'value'
            },
            series: [
                {
                    name: 'GDP(亿元)',
                    data: [48.94, 55.3, 62.04, 67.94, 71.7, 72.8, 79.8, 90.04, 92.57, 95.42],
                    type: 'line',
                    label: {
                        show: true,
                        position: 'top',
                        formatter: '{c}'
                    }
                }
            ]
        }
    },
    {
        id: 'c6',
        style: {
            width: 220,
            height: 90,
            left: 397,
            top: 100
        },
        type: 'html',
        template: `
            <div style="width: 100%;height: 100%;display: flex;flex-direction: column;justify-content: space-around;">
                <div style="font-size:22px;text-align:center;color:#FF0000;">532,167</div>
                <div style="font-size:16px;text-align:center;color:#807F7F;">今年上半年GDP(亿元)</div>
            </div>
        `
    },
    {
        id: 'c7',
        style: {
            width: 220,
            height: 90,
            left: 618,
            top: 100
        },
        type: 'html',
        template: `
            <div style="width: 100%;height: 100%;display: flex;flex-direction: column;justify-content: space-around;">
                <div style="font-size:22px;text-align:center;color:#FF9900;">463,324.76</div>
                <div style="font-size:16px;text-align:center;color:#807F7F;">去年上半年GDP(亿元)</div>
            </div>
        `
    },
    {
        id: 'c8',
        style: {
            width: 220,
            height: 90,
            left: 839,
            top: 100
        },
        type: 'html',
        template: `
            <div style="width: 100%;height: 100%;display: flex;flex-direction: column;justify-content: space-around;">
                <div style="font-size:22px;text-align:center;color:#00CC00;">12.7</div>
                <div style="font-size:16px;text-align:center;color:#807F7F;">同比增长率(%)</div>
            </div>
        `
    }
]

components/ChartComponent.vue

<template>
    <div class="box" :style="styleObj">
        <div class="chart" :id="item.id"></div>
    </div>
</template>

<script>
import * as echarts from 'echarts'
const geoJSON = require('./geojson.json')
import _ from 'lodash'

export default {
    props: {
        item: Object,
        scaleWidth: Number,
        scaleHeight: Number
    },
    data() {
        return {
            itemData: this.item,
            myChart: null
        }
    },
    computed: {
        styleObj() {
            return {
                width: this.itemData.style.width * this.scaleWidth + 'px',
                height: this.itemData.style.height * this.scaleHeight + 'px',
                top: this.itemData.style.top * this.scaleHeight + 'px',
                left: this.itemData.style.left * this.scaleWidth + 'px'
            }
        }
    },
    watch: {
        scaleWidth() {
            this.renderAgain()
        },
        scaleHeight() {
            this.renderAgain()
        },
    },
    mounted() {
        this.renderChart()
    },
    methods: {
        renderAgain() {
            if (this.myChart) {
                this.myChart.resize()
                this.myChart.dispose()
            }
            this.renderChart()
        },
        changeChildNodeStyle(childNodes) {
            for (let i = 0; i < childNodes.length; i++) {
                    let child = childNodes[i]

                    if (child.childNodes.length > 0) {
                        this.changeChildNodeStyle(child.childNodes)
                    }

                    if (child.nodeType === 1) {
                        if (child.oldFontSize !== undefined) {
                            child.style.fontSize = child.oldFontSize * this.scaleWidth + 'px'
                        } else {
                            if (!child.style.fontSize) {
                                return
                            }
                            let fontSize = child.style.fontSize.replace('px', '')
                            fontSize = Number(fontSize)
                            child.oldFontSize = fontSize
                            fontSize *= this.scaleWidth
                            child.style.fontSize = fontSize + 'px'
                        }
                    }

                    
                }
        },
        renderChart() {
            let scale = this.scaleWidth // Math.min(this.scaleWidth, this.scaleHeight)
            if (this.itemData.type === 'html') {
                let el = document.getElementById(this.itemData.id)

                let childNodes = el.childNodes
                if (childNodes.length === 0) {
                    el.innerHTML = this.itemData.template
                }
                childNodes = el.childNodes

                this.changeChildNodeStyle(childNodes)
            } else if (this.itemData.type === 'chart') {
                this.myChart = echarts.init(document.getElementById(this.itemData.id))
                let option = _.cloneDeep(this.itemData.option)

                option.title.textStyle.fontSize *= scale
                this.myChart.setOption(option)
            } else if (this.itemData.type === 'map') {
                // 中国地图数据来源:https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=100000_full
                echarts.registerMap('china', { geoJSON })
                this.myChart = echarts.init(document.getElementById(this.itemData.id))

                let arr = this.itemData.option.series[0].data
                let values = arr.map(item => item.value)
                let min = Math.min(...values)
                let max = Math.max(...values)

                let option = _.cloneDeep(this.itemData.option)
                option.title.textStyle.fontSize *= scale
                option.visualMap.min = min
                option.visualMap.max = max

                this.myChart.setOption(option)
            }
        }
    }
}
</script>

<style scoped>
.box {
    position: absolute;
    padding: 5px;
    box-sizing: border-box;
}

.chart {
    width: 100%;
    height: 100%;
    background-color: rgb(255, 255, 255);
    border-radius: 4px;
}
</style>

components/geojson.json

中国地图经纬度相关数据,数据量太大,请自行下载:https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=100000_full

说明

代码纯手写,时间紧,功能封装和容错等并没有很好地处理,有不足之处还请不要见怪,主要是理解自适应的理念。

三、DataEase

本文案例来自DataEase,今天介绍的理念也是受它启发,在此表示感谢!DataEase提供了开源的大屏可视化解决方案,包括前后台,开源项目地址:https://github.com/dataease/dataease,感兴趣的同学可以去看下源码。

本文案例的相关链接在这里:https://dataease.fit2cloud.com/#/preview/e29030f5-212f-462f-b43a-3ccdd983446b,看看一样吗?

四、总结

今天的分享的主题是完美适配的解决方案,其实有些名不符实,最多是一种理念或思想,但可操作性很强。

关于大屏可视化的六种自适应方式,已经分享完了,你学会了吗?欢迎评论区告诉我

好了,分享结束,谢谢点赞,下期再见。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2108274.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新160个crackme - 048-monkeycrackme1

运行分析 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/8e7c9973721b4df1997cc9a83e0ef2b6.png 500x) 点击注册无反应 PE分析 Delphi程序&#xff0c;32位&#xff0c;无壳 静态分析&动态调试 使用DeDeDark进行分析&#xff0c;发现Register按钮事件地址入口…

Dataframe合并大两个df如何完美融合

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 一、引言 在数据分析过程中&#xff0c;经常需要将多个DataFrame进行合并。本文将详细介绍如何使用pandas库中的merge()、concat()、join()等方法实现两个DataFrame的合并&#xff0c;以及各种方法的适用场景和优缺…

【靶场】pikachu—RCE

&#x1f3d8;️个人主页&#xff1a; 点燃银河尽头的篝火(●’◡’●) 如果文章有帮到你的话记得点赞&#x1f44d;收藏&#x1f497;支持一下哦 【靶场】pikachu—RCE 第一关 exec "ping"第二关 exec "eval" 第一关 exec “ping” 尝试 ping 一下本地12…

文生软件!国内没有任何一家大模型能做到的事,他却做到了!

书接上回&#xff0c;我们一手实测了一下阶跃星辰新出的文生图大模型Step-1X&#xff0c;效果非常的不错。 感兴趣的小伙伴们可以去看一下哈&#xff1a;[有彩蛋]大模型独角兽阶跃星辰文生图模型Step-1X上线&#xff0c;效果具说很炸裂&#xff1f;快来看一手实测&#xff01;…

24. Redis缓存问题

1. 前言 在小型项目中(例如大部分 toB 业务),Redis 被作为缓存,我们无需过多关注缓存的性能,但是对于高并发的场景(例如 toC 的在线电商业务),在商品秒杀或者库存抢购的时候,Redis 也可能存在诸多潜在的问题,例如缓存穿透、缓存雪崩。 2. 缓存问题 2.1 缓存穿透 面…

「OC」iOS事件处理流程

「OC」初识iOS事件处理流程 文章目录 「OC」初识iOS事件处理流程触摸事件触摸事件的响应周期事件 响应者UIEventUITouchUIResponder 触摸流程系统响应阶段APP响应阶段寻找最佳响应者 构成响应链 寻找最佳响应者和响应链的区别总结参考资料 触摸事件 iOS的事件有好几种&#xf…

PDF到CAD转换:四大实用工具指南!

将纸质图纸或PDF文件转化为可编辑的CAD文件是一项基本技能。无论是为了更好地进行团队协作&#xff0c;还是为了简化设计流程&#xff0c;找到一个合适的PDF转CAD工具都是至关重要的。本文将深入探讨几款主流工具的功能特色&#xff0c;并结合实际使用经验分享个人见解。 福昕…

机器之心 | 预训练无需注意力,扩展到4096个token不成问题,与BERT相当

本文来源公众号“机器之心”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;预训练无需注意力&#xff0c;扩展到4096个token不成问题&#xff0c;与BERT相当 本文提出了双向门控 SSM&#xff08;BiGS&#xff09;模型&#xff0c;…

vben admin里面换行useTable里面的columns

{title: 标题,dataIndex: systemName,width: 300, minWidth: 300,customRender: ({ text }: { text: string }) > {return ${text};},}, customRender: ({ text }: { text: string }) > { return ${text}; },这行代码. 方法② ellipsis: false,加这个进去&#xff…

半导体产业核心环节有哪些?2024年中国半导体产业研究报告大揭秘!

半导体指常温下导电性能介于导体与绝缘体之间的材料。半导体应用在集成电路、消费电子、通信系统、光伏发电、照明应用、大功率电源转换等领域。半导体产业经济则是指以半导体产品为核心的经济活动&#xff0c;包括芯片设计、制造、封装测试及应用等。它是全球经济的支柱&#…

Linux 硬件学习 s3c2440 arm920t蜂鸣器

1.查找手册时钟图&#xff0c;输入12m想要通过pll得到400m的信号 2.对比pll值&#xff0c;找到最近的为405&#xff0c;得到pll中mdiv为127&#xff0c;pdiv为2&#xff0c;sdiv为1 3.想要得到fclk400&#xff0c;hclk100&#xff0c;pclk50&#xff0c;对比分频比例&#xff0…

Unet改进24:添加DualConv||轻量级深度神经网络的双卷积核

本文内容:在不同位置添加DualConv 目录 论文简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 论文简介 卷积神经网络(CNN)架构通常对内存和计算要求很高,这使得它们在硬件资源有限的嵌入式系统中不可行。 我们提出了双卷积核(DualConv)来构建轻量级深度神经网络。DualConv结…

亚马逊云科技 Gen BI 2024-09-04 上海站QuickSight

机缘 我又来了&#xff0c;感觉不上班比上班还要忙 天天像特种工一天&#xff0c;今天有度过的充实的一天&#xff0c;上午去图书馆&#xff0c;下午去了 亚马逊云科技 Gen BI 技术体验日 。 具体照片可以去 这里看 哈哈&#xff0c;这个就是我了 商业智能的趋势 根据艾瑞咨…

WildCard平台:什么是 ChatGPT 随心用?什么是 Claude 随心用?什么是随心用全能套餐?

最近胖虎收到很多私信都在询问&#xff0c;很多人搞不清楚什么是 ChatGPT 随心用&#xff1f;什么是 Claude 随心用&#xff1f;什么是随心用全能套餐&#xff1f;下面就对三种套餐做了全面的QA解答。 如果想直接使用随心用&#xff0c;或者订阅ChatGPT&#xff0c;或者支付 C…

示波器基础知识汇总(1)

系列文章目录 1.元件基础 2.电路设计 3.PCB设计 4.元件焊接 5.板子调试 6.程序设计 7.算法学习 8.编写exe 9.检测标准 10.项目举例 11.职业规划 文章目录 前言1、电子信号2、波属性①、幅度②、相移③、周期④、频率⑤、波形正弦波方波/矩形波三角波/锯齿波脉冲复合波 3、信…

YOLOv9模型训练或测试过程中,无法打印模型的GFLOPs

项目场景&#xff1a; 在YOLOv9模型的改进中&#xff0c;常常需要替换一些模块来提高模型的精度。但在评价模型大小规模的时候需要根据模型的参数量、计算量进行评定&#xff0c;一般在模型的训练文件train.py&#xff0c;或者是test.py还有models/yolo.py都会输出这些数据。 …

idea单元测试报错找不到主类

报错截图 主要是单测中没有配置类 在下面的command line 中选择jar manifest 因为条参数过长&#xff0c;这里设置只使用主类 详细解释见&#xff1a; https://www.jianshu.com/p/8322b3b17040

Web开发的艺术:C#开发中实现代码简洁性与规范性的终极指南

一、变量的要求 变量名 1.简短有意义: 合适: student_count&#xff0c;student_ids&#xff0c;student_enable_list, water_price 不合适: numberOfItemsInTheCart, totalPriceOfTheOrderInTheShoppingCart,temp, data,list 2.变量名之间不要太像: 合适: totalAmount, disc…

传统CV算法——边缘检测算法Canny算法实战

Canny 算法 边缘&#xff1a;我的理解是在图像处理的过程中&#xff0c;针对我们图像处理的过程中&#xff0c;梯度变化以较大的地方能够让我们能够快速辨识&#xff0c;针对一个人脸&#xff0c;脸上有一些平滑的地方&#xff08;没错我针对美颜的&#xff09;&#xff0c;与…

JavaScript 条件分支语句if...else

if 语句 只有当指定条件为 true 时&#xff0c;该语句才会执行代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name…