动态刻度可视化组件实现

徐小夕 等级 662 0 0

前言

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

正文

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

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

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

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

  • react + typescript + umi-library

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

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

1. 定义基本属性类型

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

export interface TickerProps {
  width: number;
  maxHeight: number;
  percent: number;
  text: string;
  value: number;
  showValue: boolean;
  unit: string;
  lineNum: number;
  defaultColor: string;
  activeColor: string;
  textStyle: object;
  valueStyle: object;
}

2. 组件整体结构

const Ticker: React.FC<TickerProps> = function(props:TickerProps) {
  const { 
    width = 100, 
    maxHeight = 10,
    percent = 50, 
    value,
    text = '瞬时能见度', 
    showValue = true, 
    unit = 'M', 
    lineNum = 12,
    defaultColor = '#06c',
    activeColor = 'red',
    valueStyle,
    textStyle
  } = props
  return (
    <div className="ticker">
      {
        showValue &&
        <div className="value" style={valueStyle}>
          { value || 0 } <span className="unit">{ unit }</span>
        </div>
      }
      <div className="tickerGraph">
        <div className="tickerLine">

        </div>
        <div className="tickerBar"></div>
      </div>
      {
        !!text && <div className="text">{ text }</div>
      }
    </div>
  );
};

export default Ticker;

3. 视图搭建

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

4.特殊功能实现

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

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

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

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

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

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

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

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

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

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

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

更多开源体验地址

最后

如果想学习更多H5游戏, webpacknodegulpcss3javascriptnodeJScanvas数据可视化等前端知识和实战,欢迎在公号《趣谈前端》加入我们的技术群一起学习讨论,共同探索前端的边界。 动态刻度可视化组件实现

更多推荐

收藏
评论区

相关推荐

JavaScript设计模式之英雄联盟
作者:黄梵高 原文: https://juejin.cn/post/6844904165982879758 构造函数模式 简介 在Jav
C++ 运算符优先级列表
Precedence Operator Description Example Associativity 1 () \[\] \-> . :: ++ \-- Grouping operator Array access Member access from a pointer Member access f
HTTPS
### 最近网站更新为https,于是做个笔记 ### 将域名 [www.domain.com](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fwww.domain.com) 的证书文件1\_www.domain.com\_bundle.crt 、 ### 私钥文件2\_www.doma
HTTPS
楔子 谣言粉碎机前些日子发布的《[用公共WiFi上网会危害银行账户安全吗?](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fwww.guokr.com%2Farticle%2F100110%2F)》,文中介绍了在使用HTTPS进行网络加密传输的一些情况,从回复来看,争议还是有的。随着网络越
HTTPS请求
##HTTPS请求## > **HttpsUtils代码** package com.ices.utils.httpsHelp; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader;
mysql+redis+memcached
<div id="mainContent"> <div class="forFlow"> <div id="post\_detail"> <!--done--> <div id="topics"> <div class="post"> <h1 class="postTitle"> <a id="cb\_post\_title\_url" class="po
Alamofire4.x开源代码分析(二)请求参数和编码
### 请求方法 框架提供了9种方法 case options = "OPTIONS" case get = "GET" case head = "HEAD" case post = "POST" case put = "PUT" case
Android 工具表
[https://www.codota.com/](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.codota.com%2F) 代码搜索  [http://www.atool.org/httptest.php](https://www.oschina.net/action/GoT
Curl之Post Json
curl Post Json $ curl -i -X POST -H "'Content-type':'application/x-www-form-urlencoded', 'charset':'utf-8', 'Accept': 'text/plain'" -d 'json_data={"a":"aaa","b":"bbb","data
Django + Uwsgi + Nginx 的生产环境部署
Django + Uwsgi + Nginx 的生产环境部署 参考网址: [https://www.cnblogs.com/chenice/p/6921727.html](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fwww.cnblogs.com%2Fchenice%2Fp%2F
Git本地分支和远程分支关联
转载:[https://blog.csdn.net/cherishhere/article/details/52606884](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fblog.csdn.net%2Fcherishhere%2Farticle%2Fdetails%2F52606884
Http发送post(x
 ![](https://oscimg.oschina.net/oscnet/9a65d10f37c4a7f5ba0404e6ec599ef771e.png) 使用jar包: <!--commons-httpclient--> <dependency> <groupId>commons-httpclient</grou
TortorliseGit删除分支
初次使用TortorliseGit的小伙伴,怕是很难找到删除分支的菜单。本文介绍如何使用TortorliseGit删除分支。 右键项目,点击“Switch/Checkout”菜单 ![](https://waylau.com/images/post/20200322-checkout.jpg) 在点击右侧的三个小点 ![](https://wayla