动态刻度可视化组件实现

前言

之前有个网友问我了一个很有价值的问题, 有关实现数据可视化的问题, 但是这个可视化问题不是一般的柱状图, 折现图之类的,而是不规则刻度的数据可视化.所以笔者思考了一下决定自己实现一个动态刻度可视化组件的方案, 来解决这一类的需求.

正文

最初的需求是这样的: 我们只需要输入文字, 数值比例, 就能生成如上图所示的刻度图.但是作为一名有追求的程序员, 需要对问题抽象化, 形成通用的解决方案,所以我们开始重组需求: 由上图我们可以拆解为一下几个需求点:

  • 支持数值自定义
  • 数值单位自定义
  • 支持刻度组件宽度自定义
  • 支持刻度线数量自定义
  • 支持刻度变化幅度自定义
  • 传入已有进度比例,即激活区范围
  • 支持刻度样式自定义
  • 支持数值样式自定义
  • 支持自定义说明文本以及说明文本自定义

以上就是笔者挖掘的通用需求,当然有其他需求也可以渐进的增加.

确认了以上需求之后,我们开始选择技术选型, 笔者之前常用的技术栈是vue和react,所以接下来我们初步确认该组件采用如下技术方案:

  • react + typescript + umi-library

如果大家擅长使用vue, 也可以, 笔者之前也写过如何搭建vue的组件库相关的文章,感兴趣可以学习了解一下, 其本质思想是一致的.

接下来我们开始实现动态刻度可视化组件. 如果对umi不熟悉的,可以参考笔者之前写的文章从0到1教你搭建前端团队的组件系统(高级进阶必备).

1. 定义基本属性类型

由以上需求分析我们可以定义如下的属性类型:

1export interface TickerProps { 2 width: number; 3 maxHeight: number; 4 percent: number; 5 text: string; 6 value: number; 7 showValue: boolean; 8 unit: string; 9 lineNum: number; 10 defaultColor: string; 11 activeColor: string; 12 textStyle: object; 13 valueStyle: object; 14}

2. 组件整体结构

1const Ticker: React.FC<TickerProps> = function(props:TickerProps) { 2 const { 3 width = 100, 4 maxHeight = 10, 5 percent = 50, 6 value, 7 text = '瞬时能见度', 8 showValue = true, 9 unit = 'M', 10 lineNum = 12, 11 defaultColor = '#06c', 12 activeColor = 'red', 13 valueStyle, 14 textStyle 15 } = props 16 return ( 17 <div className="ticker"> 18 { 19 showValue && 20 <div className="value" style={valueStyle}> 21 { value || 0 } <span className="unit">{ unit }</span> 22 </div> 23 } 24 <div className="tickerGraph"> 25 <div className="tickerLine"> 26 27 </div> 28 <div className="tickerBar"></div> 29 </div> 30 { 31 !!text && <div className="text">{ text }</div> 32 } 33 </div> 34 ); 35}; 36 37export default Ticker;

3. 视图搭建

有关刻度可视化我们完全采用dom实现, 所以这里笔者具体分析一下如何实现刻度视图: 上图的思路就是用一个个dom来组装成随机刻度图形,所以我们只要利用css实现这个形状, 也就成功了一半.至于激活状态,我们会根据传入的数据量来决定激活范围,接下来会介绍如何渲染激活的刻度,也就是上图的红色区域.

4.特殊功能实现

因为该组件很多功能在搭建结构之后已经实现了, 这里我们唯一关注的就是css和js长度计算的问题, css实现方案有很多, 这里就不具体介绍了, 笔者这里重点介绍一下如何实现指定范围的随机高度:

1// 生成指定范围的随机高度 2const random = (min:number, max:number):number => { 3 return min + Math.random() * (max - min) 4}

动态刻度条的随机高度我们就是利用以上函数实现的, 刻度条内部实现如下:

1<div className="tickerLine" style={{borderBottomColor: defaultColor}}> 2 { 3 new Array(lineNum).fill(0).map((item:number, i: number) => { 4 let isActive = (i + 1) <= Math.floor(lineNum * percent / 100) 5 return <span 6 className="tick" 7 style={{ 8 height: random(3, maxHeight) + 'px', left: (gap + 2) * i + 'px', 9 backgroundColor: isActive ? activeColor : defaultColor 10 }}> 11 </span> 12 }) 13 } 14</div>

gap为刻度之间的间距, 由于计算刻度的位置需要一点几何知识, 公式如下:

1W = Lw * lineNum + gap * ( lineNum - 1)

其中W表示刻度总宽度, Lw为刻度线宽度, lineNum为刻度线数量.

还有一个注意点就是激活态, 笔者使用如下函数来判断刻度是否具有激活状态:

1let isActive = (i + 1) <= Math.floor(lineNum * percent / 100)

这块也非常好理解, 也就是我们传入的比率乘以线的总数量,即可求出哪些刻度线是需要激活的.

以上细节实现完成之后,我们就可以来实现有点意思的刻度可视化方案啦, 如下展示的demo:

    1. 可见度测量
    1. 正态分布模型
    1. 标尺
    1. 光栅
    1. 自定义文本样式

github地址

一个基于react的轻量级刻度线可视化组件

更多开源体验地址

最后

如果想学习更多H5游戏, webpack,node,gulp,css3,javascript,nodeJS,canvas数据可视化等前端知识和实战,欢迎在公号《趣谈前端》加入我们的技术群一起学习讨论,共同探索前端的边界。

更多推荐

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )