转+:BizCharts使用采坑教程

了不起的BizCharts

最近项目的管理后台都在用阿里粑粑开源的管理框架Ant Design Pro,说真话,还是比较好用的。该框架内部也封装了一些图标插件,但是在最近的一个项目中发现,这些图标可定制性还是差了点,不能满足客户需求。

好在它的后面也介绍了自己亲生的BizChart可视化图表组件,因为定制性比较高,但是api中的介绍又不是每个都有例子,更没有组合使用的例子,经过度娘介绍,发现这片文章备受我青睐,我怕作者哪天不高兴放弃了,所以转存了一份,顺便把自己实践到的补充到后面。

原文

作为一个前端打字员,除了绿茶婊之外,最讨厌的就是图表:一个让我伤心,一个让我难过;比这更讨厌的就是文档写得不清不楚的图表库(大概率是九年义务教育期间没有学好语文),让我又爱又恨!所以本篇博文会比较枯燥,只简单描述一下使用BizCharts的过程,当然,重要的是总结遇到的坑(遵从一个坑不踩两次,一个女生不泡两次原则)。

By the way,提到BizCharts,让我们感谢一下阿里巴巴:其开源了这个好用的(虽然偶尔不那么好用,还偶得挺经常的)的react图表库供大家使用,对使用react技术栈的前端打字员来说简直就是福音。本文不会有过多的api解释,具体的接口可以看官网文档鬼门关。

正经篇幅

刚开始,视觉设计师哄我说:“我的要求并不高,待我从前一样好”,啊呸,说错了,“我的要求是:只要能把数据用直方图展现出来就好了”,so easy

// 引入相关的组件
import { Chart, Axis, Tooltip, Geom } from 'bizcharts';

// 随便mock一下数据
const str = ['we', 'are', 'the', 'black', 'gold', 'team'];
const mockData = () => {
    let result = [];

    for (let i = 0, len = 6; i < len; i++) {
        result.push({
            xAxis: ticks[i],
            yAxis: Math.floor(Math.random() * 100)
        });
    }

    return result;
};

// 图表组件
<Chart
    width={ 600 }
    height={ 400 }
    data={ mockData() }
>
    {/* x轴,横轴,以data数据的xAxis属性值为柱子的值 */}
    <Axis name="xAxis" />
    {/* y轴,纵轴,以data数据的yAxis属性值为柱子的值 */}
    <Axis name="yAxis" />
    {/* 鼠标hover直方图柱子的时候,tooltip显示的值 */}
    <Tooltip />
    {/* 几何标记对象,主要用以描述你要画的是什么图形(直方图、折线图、饼状图、区域图):interval是直方图 */}
    <Geom
        type="interval"
        position="xAxis*yAxis"
    />
</Chart>

一波操作猛如狗,让视觉设计师看看效果:

数据可视化,BizCharts图表库入坑历程

note:此直方图每一根柱子都是单点的,也就是其反映了某个横坐标点的数据情况。加入我们需要一个连续区间柱子,那么作为xAxis的数据字段值应该为一个数组,包含两个元素,表明区间的起始值。

const mockData = () => {
        let result = [];

        for (let i = 0, len = 6; i < len; i++) {
            result.push({
                xAxis: [i + 0.01, i + 1 - 0.01], // 如果不加减0.01,那么第一根柱子的终点跟第二根柱子的起点是同一个,会感觉两个柱子粘在一起
                yAxis: Math.floor(Math.random() * 100)
            });
        }

        return result;
    };
BizChart2.jpg

视觉设计师:“emmmmmm,图表长宽定死了会不会有点僵硬啊,高度可以写死,宽度总得来个自适应吧?”

“毛闷台”

<Chart
        height={ 400 }
        data={ mockData() }
        forceFit // 我妈说了(guanfang wendang shuode),加上这个属性就可以使图表宽度自适应了,隔壁echart同学要学习一下
    >
</Chart>

效果秀一波

数据可视化,BizCharts图表库入坑历程

视觉(蜜汁微笑):“猿子,你这玩意有bug啊”

“胡说,你这傻*不会用吧”

(理直气壮)“哼哼,放大窗口图表宽度确实会自适应,但是缩小就挂掉了(并不自适应),ahhhhhh”

(谄媚)“讨厌,再给我两分钟~~让我把bug结成冰。。。”

note: 实验表明,如果Chart组件的父组件Father采用flex布局,即Father使用flex自适应宽度,那么就会出现上述的问题;所以,如果有多个图表同行并列布局,请不要使用flex布局,给Father组件的宽度设置为百分比吧,此时的forceFit就会起作用了。同时,BizCharts对重绘设置了防抖,只有当停止缩放的时候才会重绘。

数据可视化,BizCharts图表库入坑历程

(屌到飞起)“over,拿去用吧”

(一脸鄙视)“哇喔~好棒棒呀,敢不敢让我调一点点小细节,我保证就一点点!”

“Come on baby!”

  1. 鼠标hover柱子的时候,为什么柱子后面有个很丑的方框,换个颜色吧!
  2. 鼠标hover柱子的时候,出现的tooltip样式丑爆了,待会我给你设计一个吧
  3. 鼠标hover柱子的时候,柱子的颜色应该有所改变,对用户比较友好!!!
  4. ...哎,你别拿刀啊~~~

把视觉杀了之后,需求还是要做的,先解决死者的第一个遗愿。

Tooltip组件提供了一个属性crosshairs,用以设置tooltip的辅助线和辅助框;默认情况下,此属性会为’line’、‘area’、‘path’、‘areaStack’类型的Geom组件开启垂直辅助线、为‘interval’类型的Geom组件展示矩形背景框。死者说的很丑的方框就是这个!

<Tooltip crosshairs={ false }/>

好的,把框去掉了!咦,我们不是说要修改它的颜色吗?好的,改一下

<Tooltip
        crosshairs={{
            type: "rect" // 可选值:rect、x、y、cross,分别对应辅助狂、平行x轴辅助线、平行y轴辅助线,十字辅助线
            style: {
                fill: 'red', // 辅助框颜色
                shadowColor: 'red', // 辅助框周边阴影的颜色
                shadowBlur: 1, // 辅助框周边阴影的透明度
                opacity: 0 // 辅助框的透明度
            }
        }}
    />
数据可视化,BizCharts图表库入坑历程

note:假如开启的是辅助线,即type不是“rect”,那么上述的样式定义将不起作用。究其原因,看了此组件的源码之后才发现,描述辅助线样式的属性不是style对象,而是lineStyle对象,官方文档并未说明这一点。

<Tooltip
        crosshairs={{
            type: "y"
            lineStyle: {
                stroke: 'red', // 辅助线颜色
                lineWidth: 4, // 辅助线宽度,单位为px
                opacity: 1 // 辅助线透明度
            }
        }}
    />
复制代码
数据可视化,BizCharts图表库入坑历程

看起来还是很容易就实现了死者的第一个遗愿,就这样怼死了视觉,是不是太残忍了点?事已至此,继续实现他的遗愿吧。

第二个遗愿是给tooltip换个样式。既然要修改tooltip的样式,就应该继续对Tooltip组件下手。通过阅读文档,发现其还有一个itemTpl的属性,也就是可以通过这个属性定义tooltip的模板

// 定义一个模板
    // name-value是相关柱子的key-value值
    const tooltipsDisplayTpl = `
        <p class="chart-tooptip">
            <span class="chart-tooptip-right">{name}</span>
            <span>{value}</span>
        </p>
    `;

    /*
        // 重写tooltip元素的样式
        // 因为视觉已死,样式是随便搞的,就弄点黑色背景当默哀一下吧
        .g2-tooltip {
            background-color: rgba(44, 49, 68, 0.80) !important;
        }

        .chart-tooptip {
            margin: 0;
            color: white;
        }

        .chart-tooptip-right {
            margin-right: 12px;
        }
    */

    <Tooltip
        crosshairs={ false }
        itemTpl={ tooltipsDisplayTpl }
        showTitle={ false } // 去头(标题,即横轴对应的刻度),往往影响我颜值的不是我的身材,而是我的脸,所以不要脸了
    />
数据可视化,BizCharts图表库入坑历程

note:如果想自定义tooltip展示的内容,还需要设置Geom组件的tooltip属性,即将数据映射到Tooltip对象上;所以此属性值如果为false的话,就不会向Tooltip组件传递任何数据(此时Tooltip只会显示title);还可设置为字符串,展示字符串对应的数据字段;But, it's not the point,重点在于可自定义

// 定义数据返回的格式,name属性对应的是itemTpl里面的同名变量
    const getTooltipData = (xAxis, yAxis) => {
        return {
            name: xAxis,
            value: yAxis
        };
    }

    <Geom
        type="interval"
        position="xAxis*yAxis"
        tooltip={["xAxis*yAxis", getTooltipData]}
    />
数据可视化,BizCharts图表库入坑历程

第二个遗愿也实现了,愧疚感也多了一点!最主要是写代码的时候老是觉得后面有人站着盯着我看。

说不定实现所有遗愿就不会有这种感觉了呢,那就继续第三个遗愿吧:“改变鼠标hover柱子时候柱子的颜色”,翻遍了整个文档,发现没有关于hover的接口啊!看来视觉是要死不瞑目了,阿门。

就在我感觉到后背越发的凉飕飕的时候,我发现Geom组件有一个属性active

数据可视化,BizCharts图表库入坑历程

文档就真的描述了那么两句话,也没例子。急病乱投医的我只能尝试一波,设置为true,得了,hover柱子的时候柱子颜色改变了!!!

<Geom
        type="interval"
        position="xAxis*yAxis"
        tooltip={["xAxis*yAxis", getTooltipData]}
        active={ true }
    />
数据可视化,BizCharts图表库入坑历程

那如果需要自定义鼠标hover柱子的样式呢?对照着Geom文档的select属性,又尝试了一遍

<Geom
        type="interval"
        position="xAxis*yAxis"
        tooltip={["xAxis*yAxis", getTooltipData]}
        style={{ cursor: 'pointer' }} //  鼠标hover上去的时候,显示小手手,免费送的
        active={[
            true,
            {
                style: {
                    fill: 'black',  // 柱子颜色,继续默哀
                    shadowColor: 'red',  // 整体阴影颜色,包括边缘
                    shadowBlur: 1,  // 阴影的透明度
                    opacity: 0 // 柱子颜色透明度
                }
            }
        ]}
    />
数据可视化,BizCharts图表库入坑历程

(神气的)“狗子,别死了,老子搞定啦”

“靠,我都装死两天了,你敢不敢再慢一点”

“那官方文档就写了一行字:只可意会不可言传!我天分有限,意会了比较久”

“嘚瑟,看,又出bug了吧!你的表子一闪一闪的”

(掐着他脖子使劲晃)“那TM不是bug!!!”

数据可视化,BizCharts图表库入坑历程

不过话说回来,当数据更新时,从旧数据切换到新数据,会很突兀,没有缓冲过程,看着特别不舒服。我寻思着,在数据更新的时候,加个动画呗!但是初始动画生效了,更新动画就不生效了(如看官们知道解决办法,请不吝赐教)。由于赶着下班,我决定使用DataSet:一个用于管理表格数据的神器,据说更新数据的时候,其会给我弄个动画(除此以外有方便地导入非 json 数据等等功能,下文有一些例子,具体细节我没有详细去研究,以后学习了再分享)。唔好理,总之好犀利!

// 安装
    // npm install @antv/data-set

    // 引入
    import DataSet from '@antv/data-set';

    // 生成一个View实例,作为类的属性,故不要在render方法里面生成这个实例
    dv = new DataSet().createView();

    render() {
        this.dv.source(data);

        <Chart
            height={ 400 }
            data={ this.dv }
            forceFit
        ></Chart>
    }
数据可视化,BizCharts图表库入坑历程

“猿子,6啊!吃宵夜吗?我的”

“虽然不怎么饿,但是你请就不一样了,go”

吃了一桶泡面后......

“猿子,你看,宵夜也吃了·······”

“你又想干嘛···············”

简直就是饱饭思淫欲啊!!!

”我只是觉得柱子的颜色可以渐变会显得我们公司的产品更屌一点“

”狗子,你扛揍不?“

(可怜兮兮)”揍完之后可以加个渐变吗......“

”......“

”我就知道你对我最好了,我给你捶背捏大腿吧~“

”滚一边去“

<Geom
        type="interval"
        position="xAxis*yAxis"
        tooltip={["xAxis*yAxis", getTooltipData]}
        color={['xAxis', '#3DA4FF-#FFFFFF']}
    />
数据可视化,BizCharts图表库入坑历程

(掐着我脖子使劲晃)”老子要的是从上往下渐变,不是从左往右渐变“

“别.....别.....掐.....我....改....改.....”

<Geom
        type="interval"
        position="xAxis*yAxis"
        tooltip={["xAxis*yAxis", getTooltipData]}
        color={['xAxis', 'l(90) 0:#3DA4FF 1:#FFFFFF']}
    />
数据可视化,BizCharts图表库入坑历程

note:l是指线性渐变,90是指旋转九十度(即从上到下渐变,看官们可以多试试几个姿势,啊呸,多试试几个角度)

0和1标定的色值标明初始色值和终止色值,注意一点,色值不可以使用颜色名字,如“red”、“blue”等

可添加多个渐变色值,如

color="l(90) 0:#000000 0.5:#FFFFFF 1:#000000"

note:如果是area类型的Geom,那么第一种渐变方式是不起作用的,只能选用第二种

“狗子,我真要下班了”

“那个,你看都搞着渐变了,要不搞一波颜色分类”

”没得谈,goodbye!“

”宵夜我的“

”顶你个肺,又想用泡面忽悠我!!!“

”撸串,骗你我是狗“

”emmmmmm.....“

既然提到颜色分类,我们就接着提一下dv.transform 吧, dv.transform内置了一些基础的函数:filter,map,pick,rename,reverse …… 具体可自行查看文档

只需要添加 groupBy 字段,并且在传入的原始数据data中添加对应的字段classify即可轻松搞定。

dv.transform({
        groupBy: ['classify'],  // 以classify字段进行分组 
    });

”猿子,颜色还是要自定义的哦“

(白眼)

<Geom
        position={'xAxis*yAxis'}
        color={['classify', classify => {
            // 这里根据不同字段返回不同颜色
            return classify === 'test' ? 'red' : 'yellow';
        }]}
        style={{ cursor: 'pointer' }}
    />
数据可视化,BizCharts图表库入坑历程

作为一个有责任的前端打字员,有一点即使设计不要求的,我还是需要说明的,横轴的刻度值是可以自定义的

<Axis
        name={xAxis}
        label={{
            textStyle: {
                fill: 'red',  // 颜色
                textBaseline: 'top'  // 对齐基线
            },
            formatter: (val) => {
                return `${ val }\n换行了`
            }
        }}
    /> 
数据可视化,BizCharts图表库入坑历程

”狗子,撸串去!!!“

”要不还是吃个泡面????“

狗子,卒!


以下内容来自自己的总结


很显然,本人没有博主这枚猿有文化底蕴,辞藻上既不华丽丽,也没有故事性,纯属就是论事,记笔记的形式。

1. 柱状图/点图上显示文字及格式化内容

该需求需要用到Label组件,她是Geon的子组件,上代码

      <div>
        <Chart height={400} data={dv} forceFit>
          <Axis name="月份" />
          <Axis name="月均降雨量" />
          <Legend />
          <Tooltip
            crosshairs={{
              type: "y"
            }}
          />
          <Geom
            type="interval"
            position="月份*月均降雨量"
            color={"name"}
            adjust={[
              {
                type: "dodge",
                marginRatio: 1 / 32
              }
            ]}
          >
            <Label
                content={['月份*月均降雨量', (月份, 月均降雨量) => (`${月均降雨量}`)]}
                textStyle={{
                  textAlign: 'center', // 文本对齐方向,可取值为: start middle end
                  fill: '#404040', // 文本的颜色
                  fontSize: '14', // 文本大小
                  fontWeight: 'normal', // 文本粗细
                  rotate: 0, // 文字旋转
                  textBaseline: 'top', // 文本基准线,可取 top middle bottom,默认为middle
                }}
              />
            </Geom>
        </Chart>
      </div>

效果:

image.png

2. 图标上增加日期选择onChange

import React, { PureComponent } from 'react';
import { Chart, Geom, Axis, Tooltip, Label } from 'bizcharts';
import { DatePicker } from 'antd';
import numeral from 'numeral';
import moment from 'moment';
import style from './index.less';

class AppTotalUsers extends PureComponent {
  numeralCount = count => numeral(count).format('0,0.00');

  wanCount = count => {
    let data;
    if (count < 10000) {
      data = count;
    } else {
      data = this.numeralCount(count / 10000);
      data = `${data} 万`;
    }
    return data;
  };

  handleSelect = value => {
    const { callback } = this.props;
    const payload = { showDate: value };
    callback(payload);
  };

  // Can not select days before today and today
  disabledDate = current => current && current > moment().endOf('day');

  const  appChartData = [
      {
          "x": "用户中心管理",
                "y": "23715",
                "date": "2019-03-22"
            },
            {
                "x": "测试app",
                "y": "2899",
                "date": "2019-03-22"
            }
        ];

  render() {
    const { appChartData, showDate } = this.props;
    const background = {
      fill: '#FFFFFF', // 图表背景色-白色
      fillOpacity: 0, // 图表背景透明度
    };

    const appScale = {
      y: {
        alias: '人数',
        type: 'pow',
      },
    };

    return (
      <div style={{ height: 390 }}>
        <div style={{ padding: '20px', background: '#FFFFFF' }}>
          <Chart height={300} data={appChartData} scale={appScale} forceFit background={background}>
            <span className={style.mainTitle}>历史累计用户人数(人)</span>
            <DatePicker
              className={style.dateSelect}
              allowClear={false}
              onChange={this.handleSelect}
              disabledDate={this.disabledDate}
              // value={moment(appChartData[0] && appChartData[0].date, 'YYYY-MM-DD')}
              value={moment(showDate, 'YYYY-MM-DD')}
            />
            <Axis name="x" />
            <Axis name="y" visible={false} />
            <Tooltip
              crosshairs={{
                type: 'y',
                title: '人数',
              }}
            />
            <Geom type="interval" position="x*y">
              {/* 柱子上作文章用这个子组件 */}
              <Label
                content={['x*y', (x, y) => this.wanCount(`${y}`)]}
                textStyle={{
                  textAlign: 'center', // 文本对齐方向,可取值为: start middle end
                  fill: '#404040', // 文本的颜色
                  fontSize: '12', // 文本大小
                  fontWeight: 'normal', // 文本粗细
                  rotate: 0, // 文字旋转
                  textBaseline: 'top', // 文本基准线,可取 top middle bottom,默认为middle
                }}
              />
            </Geom>
          </Chart>
        </div>
      </div>
    );
  }
}

export default AppTotalUsers;

index.less文件

.chartDiv {
  padding: '0 20px';
  background-color: '#FFFFFF';
}

.mainTitle {
  font-weight: bold;
  font-size: 16px;
  padding: 10px;
}

.remark {
  font-weight: normal;
  font-size: 14px;
  padding-right: 30px;
  float: right;
}

.dateSelect {
  :global(.ant-calendar-picker-input) {
    border: none;
  }
  padding-right: 50px;
  float: right;
}

效果:


image.png

原文地址:
数据可视化,BizCharts图表库入坑历程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容

  • Echarts总结 简介:js图标库,可以兼容在pc和移动端。Echarts底层使用canvas实现,支持多图表、...
    窝头咸菜阅读 8,113评论 0 4
  • 使用GGPLOT2包进行数据可视化 Introduction简介 geom_smooth可以用于散点图,拟合一条直...
    一条很闲的咸鱼阅读 918评论 0 0
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,617评论 4 59
  • 单是约见的湖,就满是/ 我叫柳们撒出的絮/ 是独归路上的,夜半台阶旁的/ 多情而冗重的绪/ 它们嚎叫/ 螺旋行进并...
    王春蚕旋臂阅读 228评论 0 1
  • 我今天看了《怒晴湘西》的后传《云南虫谷》,拍得实在比《怒晴湘西》差多了。故事情节简单,拿两段爱情来拼凑,其中一个女...
    瑶瑶_2583阅读 1,221评论 0 0